函数式语言"/>
Scala:函数式语言
文章目录
- 1.Scala入门介绍
- 1.1 概述
- 1.2 特点
- 1.3 Scala和Java关系
- 1.4 环境搭建
- 1.4.1 window环境搭建
- 1.4.2 idea环境搭建
- 2.变量和数据类型
- 2.1 注释
- 2.2 标识符的命名规范
- 2.3 变量
- 2.4 字符串输出
- 2.4.1 字符串插值
- 2.4.2 字符串模板(多行字符串)
- 2.5 键盘输入
- 2.6 数据类型关系
- 2.7 整数类型(Byte、Short、Int、Long)
- 2.8 浮点类型(Float、Double)
- 2.9 字符类型(Char)
- 2.10 布尔类型:Boolean
- 2.11 Unit类型、Null类型和Nothing类型
- 2.12 数值类型间转换
- 2.12.1 数值类型自动转换
- 2.12.2 强制类型转换
- 2.13 数值类型和String类型间转换
- 3.运算符
- 3.1 算术运算符
- 3.2 关系运算符(比较运算符)
- 3.3 逻辑运算符
- 3.4 赋值运算符
- 3.5 位运算符
- 4.流程控制
- 4.1 分支控制if-else
- 4.1.1 单分支
- 4.1.2 双分支
- 4.1.3 多分支
- 4.2 嵌套分支
- 4.3 Switch分支结构
- 4.4 For循环控制
- 4.4.1 范围数据循环方式1
- 4.4.2 范围数据循环方式2
- 4.4.3 循环守卫
- 4.4.4 循环步长
- 4.4.5 嵌套循环
- 4.4.6 引入变量
- 4.4.7 循环返回值
- 4.5 While循环控制
- 4.6 do..while循环控制
- 4.7 多重循环控制
- 4.8 While循环中断
- 5.函数式编程
- 5.1 函数基本语法
- 5.2 函数和方法的区别
- 5.3 函数声明
- 5.4 函数参数
- 5.4.1 扩展
- 5.5 函数至简原则
- 5.6 高阶函数
- 5.7 匿名函数
- 5.8 函数柯里化&闭包
- 5.9 递归
- 5.10 控制抽象
- 5.11 惰性求值
- 6.面向对象
- 6.1 Scala包
- 6.1.1 包的命名
- 6.1.2 包说明
- 6.1.3 包对象
- 6.1.4 导包说明
- 6.1.5 访问权限
- 6.2 类和对象
- 6.2.1 定义类
- 6.2.2 属性
- 6.2.3 方法
- 6.2.4 创建对象
- 6.2.5 构造器
- 6.2.6 构造器参数
- 6.3 封装
- 6.4 继承
- 6.4.1 方法的覆写
- 不同点
- 6.4.3 多态
- 6.4.2 继承的时候构造的处理
- 6.5 抽象类、属性和抽象方法
- 6.5.1 抽象类、属性和抽象方法
- 6.5.2 匿名子类
- 6.6 单例对象(伴生对象)和伴生类
- 6.6.1 单例对象语法
- 6.6.2 apply方法
- 6.7 特质(Trait)
- 6.7.1 特质声明
- 6.7.2 特质基本语法
- 6.7.3 特质叠加
- 6.7.4 特质叠加执行顺序
- 6.7.5 特质自身类型
- 6.8 扩展
- 6.8.1 类型检查和转换
- 6.8.2 枚举类、密封类和应用类
- 6.8.3 Type定义新类型
- 7.集合
- 7.1 集合简介
- 7.1.1 不可变集合继承图
- 7.1.2 可变集合继承图
- 7.2 数组
- 7.2.1 不可变数组
- 7.2.2 可变数组
- 7.2.3 不可变数组与可变数组的转换
- 7.2.4 多维数组
- 7.3 Seq集合(List)
- 7.3.1 不可变List
- 7.3.2 可变ListBuffer
- 7.4 Set集合
- 7.4.1 不可变Set
- 7.4.2 可变mutable.Set
- 7.5 Map集合
- 7.5.1 不可变Map(有序)
- 7.5.2 可变Map
- 7.6 元组
- 7.7 集合常用函数
- 7.7.1 基本属性和常用操作
- 7.7.2 衍生集合
- 7.7.3 集合计算初级函数
- 7.7.4 集合计算高级函数
- 7.7.5 普通WordCount案例
- 7.7.6 复杂WordCount案例
- 7.8 队列
- 7.9 并行集合
- 7.10 sort排序
- 8.模式匹配
- 8.1 基本语法
- 8.2 模式守卫
- 8.3 模式匹配类型
- 8.3.1 匹配常量
- 8.3.2 匹配类型
- 8.3.3 匹配数组
- 8.3.4 匹配列表
- 8.3.5 匹配元组
- 8.3.6 匹配对象及样例类
- 8.4 变量声明中的模式匹配
- 8.5 for表达式中的模式匹配
- 8.6 偏函数中的模式匹配
- 9.泛型
- 9.1 协变和逆变
- 9.2 泛型上下限
- 9.3 上下文限定
- 9.4 视图界定
- 10.隐式转换
- 10.1 隐式转函数
- 10.2 隐式类
- 10.3 隐式参数和隐式值
- 10.4 隐式转换函数,隐式类,隐式值 的查找路径问题
- 11.异常
- 11.1 Java异常处理
- 11.2 Scala异常处理
- 12.总结
- 12.1 开发环境
- 12.2 变量和数据类型
- 12.3 流程控制
- 12.4 函数式编程
- 12.5 面向对象
- 12.6 集合
- 12.7 模式匹配
- 12.8 异常
- 12.9 隐式转换
- 12.10 泛型
- 12.11 扩展
1.Scala入门介绍
1.1 概述
Scala由马丁·奥德斯基(Martin Odersky)设计,是一门多范式的编程语言,一种类似java的编程语言 ,设计初衷是实现可伸缩的语言 、并集成面向对象编程和函数式编程的各种特性
1.2 特点
Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。
1)Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。
2)Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。
3)Scala单作为一门语言来看,非常的简洁高效。
4)Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源于Java,同时马丁·奥德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中。
1.3 Scala和Java关系
- Scala可以使用java的类库和自己的类库
- Scala编译完成后也是字节码,直接运行在JVM上
1.4 环境搭建
1.4.1 window环境搭建
1.准备java环境
2.解压 scala.zip包
3.配置环境变量
- SCALA_HOME
- PATH
1.4.2 idea环境搭建
1.安装支持scala开发的插件(装完重启)
2.创建maven project
3.添加 scala 的支持
4.创建一个 object
2.变量和数据类型
2.1 注释
含义:用于注解说明解释程序的文字,注释提高了代码的阅读性
1.基本语法
(1)单行注释://
(2)多行注释:/* */
(3)文档注释:/****/
2.代码规范
(1)使用一次tab操作,实现缩进,默认整体向右边移动,用shift+tab整体向左移
(2)或者使用ctrl + alt + L来进行格式化
(3)运算符两边习惯性各加一个空格。比如:2 + 4 * 5。
(4)一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅
2.2 标识符的命名规范
含义:Scala对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符
1.命名规则
(1)以字母或者下划线开头,后接字母、数字、下划线
(2)以操作符开头,且只包含操作符(+ - * / # !等)
(3)第一种和第二种拼接,第一种在前,二者以下划线分隔
(4)用反引号``可包括任意字符串,即使是关键字(39个)也可以
2.案例参考
hello // ok
hello12 // ok
1hello // error
h-b // error
x h // error
h_4 // ok
_ab // ok
Int // ok , 因为在Scala Int是预定义的字符,不推荐
Float // ok
_ // error ,单独一个下划线不可以作为标识符
Abc // ok
+*- // ok
+a // error,a需在前
$a // ok , 但不要让scala的标识符出现$,因为scala编译器会使用$
` ` //ok, 反引号,可包括任意字符串,定义标识符
3.Scala关键字(39个)
- package, import, class, object, trait, extends, with, type, for
- private, protected, abstract, sealed, final, implicit, lazy, override
- try, catch, finally, throw
- if, else, match, case, do, while, for, return, yield
- def, val, var
- this, super
- new
- true, false, null
2.3 变量
1.基本语法
var | val 变量名 [: 变量类型] = 变量值
说明:在Scala中声明一个变量时,可以不指定类型,编译器根据值确定
2.案例说明
(1)声明变量时,类型可以省略(编译器自动推导,即类型推导)
(2)类型确定后,就不能修改,说明Scala是强数据类型语言
(3)变量声明时,需要初始值
package com.jaffe.chapter03
object TestVar {def main(args: Array[String]): Unit = {//(1)声明变量时,类型可以省略(编译器自动推导,即类型推导)var age = 18age = 30//(2)类型确定后,就不能修改,说明Scala是强数据类型语言。// age = "tom" // 错误//(3)变量声明时,需要初始值// var name //错误}
}
(4)在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改
object TestVar {def main(args: Array[String]): Unit = {var num1 = 10 // 可变val num2 = 20 // 不可变num1 = 30 // 正确//num2 = 100 //错误,因为num2是val修饰的}
}
(5)val修饰的变量在编译后,等同于加上final通过反编译看下底层代码
object TestVar {var num1 = 10 // 可变val num2 = 20 // 不可变def main(args: Array[String]): Unit = {num1 = 30 // 正确//num2 = 100 //错误,因为num2是val修饰的}
}
通过反编译软件,得到对应的底层的.class是
public final class TestVar$
{public static final MODULE$;private int num1;private final int num2;
(6)var修饰的对象引用可以改变,val修饰的则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)
object TestVar {def main(args: Array[String]): Unit = {// p1是var修饰的,p1的属性可以变,而且p1本身也可以变var p1 = new Person()p1.name = "zzh"p1 = null// p2是val修饰的,则p2的属性可以变,但是p2本身不可变(即p2的内存地址不能变)val p2 = new Person()p2.name="xiaolian"//p2 = null // 错误的,因为p2是val修饰的}
}class Person{var name : String = "jaffe"
}
2.4 字符串输出
1.基本语法
(1)字符串,通过+号连接
(2)printf用法:字符串,通过%传值
(3)字符串,通过$引用
2.案例说明
package com.jaffe.chapter02
object TestCharType {def main(args: Array[String]): Unit = {var name: String = "jinlian"var age: Int = 18//(1)字符串,通过+号连接println(name + " " + age)//(2)printf用法字符串,通过%传值。printf("name=%s age=%d\n", name, age)//(3)字符串,通过$引用println(s"name=$name age=$age")println(s"""name=${name}age=${age}""")}
}
2.4.1 字符串插值
1.s插值(重要)
val a: Int = 10
val b: Int = 20
//s插值
val res: String = s"a=$a, b=$b"println(res)
//输出 a=10, b=20
2.raw插值
var w = raw"\r \n \t"println(w)//输出 \r \n \t
2.4.2 字符串模板(多行字符串)
var c ="""|111|222|333""".stripMarginprintln(c)
//输出
111
222
333
2.5 键盘输入
在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取
1.基本语法
StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()
2.案例说明
需求:可以从控制台接收用户信息,【姓名,年龄,薪水】
import scala.io.StdIn
object TestInput {def main(args: Array[String]): Unit = {// 1 输入姓名println("input name:")var name = StdIn.readLine()// 2 输入年龄println("input age:")var age = StdIn.readShort()// 3 输入薪水println("input sal:")var sal = StdIn.readDouble()// 4 打印println("name=" + name)println("age=" + age)println("sal=" + sal)}
}
Java输入语法
// 从键盘读数据
// 1. java: 使用System.in直接读, 做一些封装
val reader = new BufferedReader(new InputStreamReader(System.in))
val line: String = reader.readLine()
println(line)
// 2. java: jdk 1.5之后, Scanner
val scanner = new Scanner(System.in)
val line2: String = scanner.nextLine()
println(line2)
2.6 数据类型关系
Scala数据类型关系总结
- Scala中一切数据都是对象,都是Any的子类
- Scala中数据类型分为两大类:数值类型(AnyVal)、引用类型(AnyRef),不管是值类型还是引用类型都是对象
- Scala数据类型仍然遵守低精度的值类型向高精度值类型自动转换(隐式转换)
- Scala特殊的类型之Null,它只有一个实例就是Null,它是所有引用类型(AnyRef)的子类
- Scala特殊类型之Nothing,是所有数据类型的子类,主要在一个函数没有正常返回值使用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数
2.7 整数类型(Byte、Short、Int、Long)
Scala的整数类型就是用于存放整数值的,比如12,30,3456等等
1.整型分类
数据类型 | 描述 |
---|---|
Byte [1] | 8位有符号补码整数。数值区间为 -128 到 127 |
Short [2] | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int [4] | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long [8] | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 = 2的(64-1)次方-1 |
2.案例说明
(1)Scala各整数类型有固定的表数范围和字段长度,不受具体操作的影响,以保证Scala程序的可移植性。
object TestDataType {def main(args: Array[String]): Unit = {// 正确var n1:Byte = 127var n2:Byte = -128// 错误// var n3:Byte = 128// var n4:Byte = -129}
}
(2)Scala的整型,默认为Int型,声明Long型,须后加‘l’或‘L’
object TestDataType {def main(args: Array[String]): Unit = {var n5 = 10println(n5)var n6 = 9223372036854775807Lprintln(n6)}
}
(3)Scala程序中变量常声明为Int型,除非不足以表示大数,才使用Long
2.8 浮点类型(Float、Double)
Scala的浮点类型可以表示一个小数,比如123.4f,7.8,0.12等等
1.浮点型分类
数据类型 | 描述 |
---|---|
Float [4] | 32 位, IEEE 754标准的单精度浮点数 |
Double [8] | 64位 IEEE 754标准的双精度浮点数 |
2.案例实操
(1)Scala的浮点型常量默认为Double型,声明Float型常量,须后加‘f’或‘F’。
object TestDataType {def main(args: Array[String]): Unit = {// 建议,在开发中需要高精度小数时,请选择Doublevar n7 = 2.2345678912fvar n8 = 2.2345678912println("n7=" + n7)println("n8=" + n8)}
}
//运行的结果
n7=2.2345679
n8=2.2345678912
2.9 字符类型(Char)
1.基本说明
字符类型可以表示单个字符,字符类型是Char,16位无符号Unicode字符(2个字节),区间值为U+0000到U+FFFF
2.案例说明
(1)字符常量是用单引号 ’ ’ 括起来的单个字符
(2)可以直接给Char赋一个整数,然后输出时,会按照对应的unicode字符输出
object TestCharType {def main(args: Array[String]): Unit = {//(1)字符常量是用单引号 ' ' 括起来的单个字符。var c1: Char = 'a'println("c1=" + c1)//(2)可以直接给Char赋一个整数,然后输出时,会按照对应的unicode字符输出println("c1码值=" + c1.toInt)}
}
(3)Char类型是可以进行运算的,相当于一个整数,因为它都对应有Unicode码。
object TestCharType {def main(args: Array[String]): Unit = {var c2: Char = 98 // 正确,因为直接将一个数值给char,编译器只判断是否越界var c3: Char = 'a' + 1 // 错误,Int高->char低,编译器判断类型var c4: Char = ('a' + 1).toChar}
}
(4)\t :一个制表位,实现对齐的功能
(5)\n :换行符
(6)\ :表示
(7)" :表示"
object TestCharType {def main(args: Array[String]): Unit = {//(4)\t :一个制表位,实现对齐的功能println("姓名\t年龄")//(5)\n :换行符println("西门庆\n潘金莲")//(6)\\ :表示\println("c:\\岛国\\avi")//(7)\" :表示"println("同学们都说:\"我最帅\"")}
}
2.10 布尔类型:Boolean
1.基本说明
(1)布尔类型也叫Boolean类型,Booolean类型数据只允许取值true和false
(2)boolean类型占1个字节
2.案例说明
object TestBooleanType {def main(args: Array[String]): Unit = {var isResult : Boolean = falsevar isResult2 : Boolean = true}
}
2.11 Unit类型、Null类型和Nothing类型
1.基本说明
数据类型 | 描述 |
---|---|
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成() |
Null | null , Null 类型只有一个实例值null |
Nothing | Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
2.案例说明
(1)Null类只有一个实例对象,Null类似于Java中的null引用。Null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)
object TestDataType {def main(args: Array[String]): Unit = {//null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)var n1: Int = null // 错误println("n1:" + n1)var cat = new Cat();cat = null // 正确}
}
class Cat {}
(2)Unit类型用来标识过程,也就是没有明确返回值的函数,类似于Java里的void。Unit只有一个实例——( ),这个实例也没有实质意义
object TestSpecialType {def main(args: Array[String]): Unit = {def sayOk : Unit = {// unit表示没有返回值,即voidprintln("say ok")}sayOk}
}
(3)Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
object TestSpecialType {def main(args: Array[String]): Unit = {def test() : Nothing={throw new Exception()}test}
}
2.12 数值类型间转换
2.12.1 数值类型自动转换
当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:
1.基本说明
(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
(2)当我们把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
(3)(byte,short)和char之间不会相互自动转换。
(4)byte,short,char他们三者可以计算,在计算时首先转换为int类型。
2.案例实操
object TestValueTransfer {def main(args: Array[String]): Unit = {//(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数值类型,然后再进行计算。var n = 1 + 2.0println(n) // n 就是Double//(2)当我们把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。var n2 : Long = 1L//var n3 : Int = n2 //错误,原因不能把高精度的数据直接赋值和低精度。//(3)(byte,short)和char之间不会相互自动转换。var n4 : Byte = 1//var c1 : Char = n4 //错误//(4)byte,short,char他们三者可以计算,在计算时首先转换为int类型。var n5 : Byte = 1var c2 : Char = 1// var n : Short = n5 + c2 //当n5 + c2 结果类型就是int// var n6 : Short = 10 + 90 //错误var n7 : Short = 100 //正确}
}
注意:Scala还提供了非常强大的隐式转换机制(隐式函数,隐式类等)
2.12.2 强制类型转换
1.基本说明
自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
java : int num = (int)2.5
scala : var num : Int = 2.7.toInt
2.案例说明
(1)当进行数据的从大——>小,就需要使用到强制转换
(2)强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
object TestForceTransfer {def main(args: Array[String]): Unit = {//(1)当进行数据的从大——>小,就需要使用到强制转换var n1: Int = 2.5.toInt // 这个存在精度损失//(2)强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级var r1: Int = 10 * 3.5.toInt + 6 * 1.5.toInt // 10 *3 + 6*1 = 36var r2: Int = (10 * 3.5 + 6 * 1.5).toInt // 44.0.toInt = 44println("r1=" + r1 + " r2=" + r2)}
}
(3)Char类型可以保存Int的常量值,但不能保存Int的变量值,需要强转
(4)Byte和Short类型在进行运算时,当做Int类型处理
object TestForceTransfer {def main(args: Array[String]): Unit = {//(3)Char类型可以保存Int的常量值,但不能保存Int的变量值,需要强转var c2: Char = 98 // 正确,因为直接将一个数值给char,编译器只判断是否越界var c3: Char = 'a' + 1 // 错误,Int高->char低,编译器判断类型var c4: Char = ('a' + 1).toChar//(4)Byte和Short类型在进行运算时,当做Int类型处理。var a : Short = 5// a = a-2 // 错误, Int->Shortvar b : Byte = 3// b = b + 4 // 错误,Int->Byte}
}
2.13 数值类型和String类型间转换
1.基本说明
在程序开发中,我们经常需要将基本数值类型转成String类型。或者将String类型转成基本数值类型。
2.案例说明
(1)基本类型转String类型(语法:将基本类型的值+"" 即可)
(2)String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)
object TestStringTransfer {def main(args: Array[String]): Unit = {//(1)基本类型转String类型(语法:将基本类型的值+"" 即可)var str1 : String = true + ""var str2 : String = 4.5 + ""var str3 : String = 100 +""//(2)String类型转基本数值类型(语法:调用相关API)var s1 : String = "12"var n1 : Byte = s1.toBytevar n2 : Short = s1.toShortvar n3 : Int = s1.toIntvar n4 : Long = s1.toLong}
}
3.注意事项
在将String类型转成基本数值类型时,要确保String类型能够转成有效的数据,比如我们可以把"123",转成一个整数,但是不能把"hello"转成一个整数。
3.运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等
在scala中, 没有真正的运算符, 所有的运算符其实都是对象的方法.
当调用方法的时候, 省略了 . 和 圆括号的时候, 方法就成了运算符了.
- 方法没有优先级
- 运算符有优先级
- 运算符还有结合性(左结合和右结合)
更多推荐
Scala:函数式语言
发布评论