华为云建网站,dw制作一个手机网站模板,手机网站进不去怎么解决,西安个人做企业网站第一篇https://blog.csdn.net/m0_74021449/article/details/144887921 2.2 Scala的变量及函数
2.2.1变量定义与基本类型
变量声明
变量首次定义必须使用关键字var或者val#xff0c;二者的区别是val修饰的变量禁止被重新赋值#xff0c;它是一个只读的变量。首次定义变量时…第一篇https://blog.csdn.net/m0_74021449/article/details/144887921 2.2 Scala的变量及函数
2.2.1变量定义与基本类型
变量声明
变量首次定义必须使用关键字var或者val二者的区别是val修饰的变量禁止被重新赋值它是一个只读的变量。首次定义变量时必须赋值进行初始化。var类型的变量重新赋值时新旧必须是同一个类型而val类型变量无法被重新赋值。变量定义具有覆盖性后声明的变量会覆盖前面的变量。
Scala推荐使用val定义变量函数式编程的思想之一就是传入函数的参数不应该改变。需要说明的是使用val定义的变量并不是不可变而是这个指向关系不可变。当这个变量被声明变量指向的对象就是唯一确定的但这个对象本身可以改变只是变量指向的位置不可变。
基本类型
Scala作为一种静态语言在编译时会检查每个对象的类型类型不匹配的非法操作会报错。Scala定义了一些标准类型
类型说明Byte8bit有符号整数补码表示范围是-27~27-1Short16bit有符号整数补码表示范围是-215~215-1Int32bit有符号整数补码表示范围是-231~231-1Long64bit有符号整数补码表示范围是-263~263-1Char16bit无符号字符Unicode编码表示范围是0~216-1String字符串类型属于java.bang包Float32bit单精度浮点数Double64bit双精度浮点数Boolean布尔值true or false
定义变量时可以指定类型也可以让编译器自动推断。显式指定类型的示例
scala val x: Int 123
val x: Int 123scala val y: Long 123
val y: Long 123
整数字面量
如果单独出现数字没有任何说明默认推断为Int类型结尾有l或L的推断为Long类型以0x开头的认为是十六进制不区分大小写。Byte和Short类型需要显示指定
scala val x 100
val x: Int 100
scala val y 100L
val y: Long 100
scala val z: Byte 200
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val z: Byte 200| ^^^| Found: (200 : Int)| Required: Byte|| longer expla
Byte类型最大不超过127超过限制的赋值将报错
浮点数字面量
浮点数字面量都是十进制的默认是Double类型En或en表示科学计数法10的n次方末尾加一个f或F表示FloatD或d表示Double。Double字面量不能赋值给Float类型变量。
scala val x: Float -3.2
val x: Float -3.2
scala val x -3.2
val x: Double -3.2
scala val x: Float 3.2D
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val x: Float 3.2D| ^^^^| Found: (3.2d : Double)| Required: Float|| longer explanation available when compiling with -explain
1 error found
字符字面量和字符串字面量
以单引号括住的一个字符表示一个字符字面量采用Unicode编码也可以使用\u编号来构建一个字符本书说明Unicode编码可以出现在名称命名处但在最新版本Scala编译器中会报错
scala val a a
val a: Char a
scala val \u0041 a
-- [E032] Syntax Error: ------------------------------------------------------------------------------------------------
1 |val \u0041 a| ^| pattern expected|| longer explanation available when compiling with -explain
字符串字面量是用双引号“”括住的字符序列长度是任意的。字符和字符串都支持转义字符。
字符串插值
表达式可以被嵌入在字符串字面量中被求值有三种实现方法一种是s插值器一种是raw插值器一种是f插值器。
s插值器形如 s……${表达式}……其中花括号可以不加但只会识别美元符号到首个非标识字符字母、数字、下划线和操作符的组合交标识符以及字符串对于非标识字符如果想要求值必须使用花括号
scala val name Jia
val name: String Jiascala sName $name
val res3: String Name Jiascala sResult ${12}
val res4: String Result 3
raw插值器和s插值器类似区别是不识别转义字符。
f插值器使用方法更灵活支持格式控制
scala printf(f${math.Pi}%.5f)
3.14159~
2.2.2函数及其几种形式
函数的定义
不多说直接看代码
scala def max(x : Int, y: Int): Int {| if(x y)| x| else| y| }
def max(x: Int, y: Int): Int
说明x,y是输入参数形参后面跟的是它们的类型Int{}是函数体表示返回是一个Int类型整数。
备注左侧的|只是编译器自己生成的用于多行的代码并不是语法体系中的一部分。 分号推断语句末尾的分号是可选的编译器会自动推断分号。如果一行有多条语句则必须用分号隔开。 函数的返回结果return关键字是可选的编译器自动为函数体中的最后一个表达式加上return建议不要显示声明return。返回结果的类型也可以自动推断也就是说上面的Int {}Int也是可以省略的。Uint类型表示无返回值它不是必须的编译器也可以自动推断但如果显式声明Uint则即便有可以返回的值也不会返回任何值。 等号与函数体函数体是花括号括起来的部分里面有多条语句可以自动推断分号返回最后一个表达式。当函数的返回类型没有显示声明等号可以省略但此时返回类型会变成Uint建议不要省略等号并且用显示声明返回类型。 无参函数无参函数可以写空括号作为参数列表也可以不写但如果没有空括号调用的时候禁止写空括号。
方法
方法指定义在classobjecttrait中的函数成为成员函数或方法这与其他面向对象特性的语言一致。
嵌套函数
函数体内部可以嵌套定义内部函数但无法被外界访问。
函数字面量
函数式编程认为函数的地位和一个Int值String值是一样的因此函数也可以成为一个函数的参数或返回值也可以把函数赋值给一个变量。函数字面量是一种匿名函数它可以存储在变量中成为函数参数或者当作返回值返回定义形式是
{参数1参数1类型参数2参数2类型...} {函数体}
它可以更精简地使用用下划线作为占位符替代参数只保留函数体
scala val f (_: Int) (_: Int)
val f: (Int, Int) Int Lambda/0x00000003015d55a86816b0cbscala f(1,2)
val res5: Int 3
用def定义的函数和函数字面量都可以以函数为参数返回函数。
scala val add (x:Int) {(y:Int) x y}
val add: Int Int Int Lambda/0x00000003015d634820f1e26scala add(1)(10)
val res6: Int 11
这里是函数的嵌套第一个函数表示输入是x类型是Int函数体是(y:Int) xy这是一个函数字面量它的输入是y类型是Int函数体是xy并且把这个表达式结果返回。如果调用add(1)则返回的是(y:Int)1y这个函数字面量。
scala def aFunc(f:Int Int) f(1) 1
def aFunc(f: Int Int): Int
scala aFunc(xx1)
val res7: Int 3
aFunc的参数f是一个函数它的输入类型是Int返回类型也是Int调用时传入的参数是函数字面量xx1首先计算f(1)2再计算返回值是3。
部分应用函数
上面的函数字面量实现了函数作为一等值的功能使用def定义的函数也具有相同的功能只不过需要借助部分应用函数的形式来实现。部分应用函数的意思就是给出函数的一部分参数使其可以赋值给变量或者当作函数参数进行传递。废话不多数直接上代码
scala def sum(x:Int,y:Int,z:Int) : Int {x y z}
def sum(x: Int, y: Int, z: Int): Int
scala val a1 sum(4,5,6)
val a1: Int 15
scala val a2 sum(4,_:Int,6)
val a2: Int Int Lambda/0x000000030167d3a0c3acda3
scala a2(5)
val res12: Int 15
scala val a3 sum _
1 warning found
-- Warning: ------------------------------------------------------------------------------------------------------------
1 |val a3 sum _| ^^^^^| The syntax function _ is no longer supported;| you can simply leave out the trailing _
val a3: (Int, Int, Int) Int Lambda/0x00000003016767e02c427287
scala val a3 sum
val a3: (Int, Int, Int) Int Lambda/0x0000000301676e1068603829
scala a3(4,5,6)
val res9: Int 15
注意书中的写法 sum _在最新版的编译器中不被支持现在无需写下划线只需要把函数名直接赋值给变量即可直接调用。
scala def needSum(f:(Int,Int,Int) Int) f(1,2,3)
def needSum(f: (Int, Int, Int) Int): Int
scala needSum(sum)
val res13: Int 6
这里我们已经逐渐能够感受到函数式编程的魅力当理解这种调用方式后将会有很灵活的应用。
闭包
一个函数除了使用它的参数以外还可以使用定义在函数以外的其他变量其中函数的参数成为绑定变量函数以外的变量称为自由变量这样的函数称为闭包。函数捕获的自由变量是函数定义之前的自由变量若后面出现新的同名自由变量将前面的自由变量将其覆盖函数与其无关。但如果自由变量是用var创建的可变对象那么闭包随之改变。
scala var a1 1
var a1: Int 1
scala val a2 100
val a2: Int 100
scala val add1 (x : Int) x a1
val add1: Int Int Lambda/0x000000030167fb0823b456ac
scala val add2 (x : Int) x a2
val add2: Int Int Lambda/0x00000003016843f0525b416f
scala add1(1)
val res14: Int 2
scala add2(1)
val res15: Int 101
scala a1 100
a1: Int 100
scala add1(1)
val res16: Int 101
scala var a1 1
var a1: Int 1
scala add1(1)
val res17: Int 101
scala val a2 1
val a2: Int 1
scala add2(1)
val res18: Int 101
阅读这段程序的对比已经很明显地了解到它的性质。在后面改变var变量的值闭包随之改变但对于var和val变量重新定义将前面的覆盖闭包的值不会随之改变。
函数的特殊调用形式 具名参数函数调用时传入的参数是按照先后顺序传递的但如果显式声明参数的名字可以无视参数顺序。按位置传递的参数和按名字传递的参数可以混用。 默认参数值函数定义时可以给参数一个默认值如果调用函数缺省了这个参数会使用默认值。 重复参数允许把函数的最后一个参数标记为重复参数形式在最后一个参数的类型后面加上星号。
柯里化
对于大多数编程语言而言函数只能有一个参数列表但是列表中可以有若干用逗号间隔的参数。Scala的特性柯里化允许一个函数可以有任意个参数列表它与另一个语法搭配使用即当参数列表中只有一个参数时调用该函数时允许单个参数不用圆括号括起来改用花括号也可以。
scala def add(x:Int)(y:Int)(z:Int) xyz
def add(x: Int)(y: Int)(z: Int): Intscala add(1)
val res19: Int Int Int Lambda/0x0000000301686b407ece1800scala add(1)(2)
val res20: Int Int Lambda/0x00000003016872f03b3e9814scala add(1)(2)(3)
val res21: Int 6scala add(1)(2){3}
val res22: Int 6scala add{1}(2)(3)
val res23: Int 6
在这里我们看出来其实柯里化就是把它处理成了一个嵌套的函数。
传名参数
如果一个函数是无参函数调用函数时传递进去的函数字面量可以只写函数体。
//常规调用方法
scala val a1 1
val a1: Int 1
scala val a2 2
val a2: Int 2
scala def add(f: () Int) {a1 a2 f()}
def add(f: () Int): Int
scala add(() 1)
val res24: Int 4
//传名参数调用方法
scala def add2(f: Int) {a1 a2 f}
def add2(f: Int): Int
scala add2(1)
val res26: Int 4
注这里传入的f函数是一个没有输入直接返回传入的值的函数。
这两种版本都是在使用到传入的函数时才会计算这个函数中的表达式但如果改写成下面这样去掉那么就变成先计算表达式再传入值。
scala def add3(f:Boolean) {| if(f)| a1 a2| else| 0| }
def add3(f: Boolean): Int
scala add3(12)
val res27: Int 3
scala add3(12)
val res28: Int 0
scala add3(1/0)
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |add3(1/0)| ^^^| Found: Int| Required: Boolean|| longer explanation available when compiling with -explain
1 error found