Scala 基础

关注我的公众号c137Lab获取更多相关内容

在这里插入图片描述

一、变量与基本类型

1. 变量

Scala 定义变量的两个关键字:"var"与“val”,var 可重新赋值,val 禁止重新赋值(只读)。定义多个变量用逗号分隔以批量赋值,var 变量在重新赋值时必须保持类型一致。

val x,y,z = 1 √
x = 234    ×
var x = 1 √
x = 123   √
x = "abc" ×
  • 赋给变量的对象本身也存在可变和不可变之分,即使是 val 变量也可以被赋予一个可变对象,这个可变对象是可以被修改的,但事实上这只是旧对象发生了改变,并没有产生任何新对象。

  • Scala 鼓励 val 类型,因为其是函数式编程。

2. 基本类型

编译器会在变量赋值时自动推理类型,也可以在赋值时自己指定。

Byte 8 bit signed int
Short 16 bit signed int
Int 32 bit signed int
Long 64 bit signed int
Char 16 bit Unicode char
String 字符串 belongs to java.lang
Float 32 bit 单精度浮点
Double 64 bit 双精度浮点
Boolean 布尔值,True or False

下面是一些实例:

scala> val x:Int = 123
x:Int = 100

scala> val b = 0X123Abc
b: Int = 1194684

scala> val d = 200L
d: Long = 200

scala> val a = 1.2E3
a: Double = 1200.0

scala> val b = -3.2f
b: Float = -3.2

scala> val a = 'A'
a: Char = A

scala> val b = '\u0041'
b: Char = A

使用三个双引号包裹的字符串中可以包含双引号且不解读转义字符。

字符串插值实例:

scala> val name = "ABC"
name: String = ABC

scala> println(s"$name DEFG")
ABC DEFG

scala> s"\\\\"
res1: String = \\

scala> raw"\\\\"
res2: String = \\\\

scala> printf(f"${math.Pi}%.5f")
3.14159

二、Function & Method

1. 定义Method

用实例简单地说明 Scala 的Method定义方式即:

用“def”开始Method定义
       | Method名
       |   |  参数及参数类型
       |   |        |   Method返回结果的类型
       |   |        |          |  等号
       |   |        |          |   |
      def max(x: Int, y: Int): Int = {
    
    
        if(x > y)
          x
        else  |
          y   | 
      }       |
              |
       花括号里定义Method体

Scala 中不建议显示声明 return ,尽管你可以这样做。返回结果的类型也能够自动推断,但是有一个特殊的返回类型——Unit,可以类比于 C 中的 Void,不会返回任何结果:

scala> def nothing(x: Int, y: Int): Unit = {
    
     x + y }
nothing: (x: Int, y: Int)Unit

scala> nothing(1, 2)

scala>

如果一个Method没有参数,那么可以写一个空括号作参数列表,也可以不写。如果有空括号,那么调用时可以写也可以不写空括号;如果没有空括号,那么调用时就一定不能写空括号。原则上,无副作用的无参Method省略括号,有副作用的无参Method添加括号,这提醒使用者需要额外小心。

Scala 允许嵌套Method,但是内层Method的作用域是局部的,不可以被外部调用,局部Method可以直接使用外层Method的参数。

2. Function

Function的地位与变量的地位是相同的,Function是一种匿名函数的形式,它可以储存在变量中,成为Function与Method的参数或者当作其返回值。在定义Function时可以使用下划线代替参数,实例如下:

scala> val f = (_:Int) + (_:Int)
f:(Int,Int) => Int = $$Lambda$1072/1534177037@fb42c1c

scala> f(1,2)
res0:Int = 3

所有 Scala 中的Method和Function都可以将一个Function作为一个返回结果(返回函数的函数)下面是两个例子

scala> val add = (x: Int) => {
    
     (y: Int) => x + y }
add: Int => (Int => Int) = $$Lambda$1192/1767705308@55456711

scala> add(1)(10)
res0: Int = 11

scala> def aFunc(f: Int => Int) = f(1) + 1
aFunc: (f: Int => Int)Int

scala> aFunc(x => x + 1)
res1: Int = 3

第一个例子中的 add 返回值是Function “(y: Int) => x + y” ,第二个 aFunc 的参数 f 是一个Function返回值 “f: Int => Int”。

3. 将 Method 转换为 Function

Method 也可以实现和变量相等的地位,但是要通过一定的转换实现,实例如下:

scala> def sum(x: Int, y: Int, z: Int) = x + y + z
sum: (x: Int, y: Int, z: Int)Int

scala> val a = sum(1, 2, 3)
a: Int = 6

scala> val b = sum(1, _: Int, 3)
b: Int => Int = $$Lambda$1204/1037479646@5b0bfe86

scala> b(2)
res0: Int = 6

scala> val c = sum _
c: (Int, Int, Int) => Int = $$Lambda$1208/1853277442@5e4c26a1

scala> c(1, 2, 3)
res1: Int = 6

注意,在不给出任何参数时,下划线和 Method 名之间必须有空格,该下划线在需要该 Method 作入参的地方可以省略,实例如下:

scala> def needSum(f: (Int, Int, Int) => Int) = f(1, 2, 3)
needSum: (f: (Int, Int, Int) => Int)Int

scala> needSum(sum _)
res2: Int = 6

scala> needSum(sum)
res3: Int = 6

4. 闭包

闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。实例如下:

scala> var factor = 3  
factor: Int = 3

scala> val multiplier = (i:Int) => i * factor
multiplier: (i:Int)Int

scala> multiplier(1)
res1: Int = 3

5. 函数的特殊调用形式

Ⅰ. 具名参数

在调用函数时显示声明参数名并给予其赋值可以无视参数顺序。按位置传递的参数和按名字传递的参数可以混用。

scala> def max(x: Int, y: Int, z: Int) = {
         |     if(x > y && x > z) println("x is maximum")
         |     else if(y > x && y > z) println("y is maximum")
         |     else println("z is maximum")
         |  }
max: (x: Int, y: Int, z: Int)Unit

scala> max(1, z = 10, y = 100)
y is maximum 

Ⅱ. 默认参数值

定义参数时给参数赋值即可实现默认参数值

scala> def max(x: Int = 1, y: Int, z: Int) = {
         |     if(x > y && x > z) println("x is maximum")
         |     else if(y > x && y > z) println("y is maximum")
         |     else println("z is maximum")
         |  }
max: (x: Int, y: Int, z: Int)Unit

scala> max(z = 10, y = 100)
y is maximum 

Ⅲ. 重复参数

在最后一个参数的类型后加星号即可标记其为重复参数,可以在调用函数时传入任意个相同类型的元素,但是不能传入该类型的 Array,否则会报错

scala> def addMany(msg: String, num: Int*) = {
         |     var sum = 0
         |     for(x <- num) sum += x
         |     println(msg + sum)
         |  }
addMany: (msg: String, num: Int*)Unit

scala> addMany("sum = ", 1, 2, 3)
sum = 6

scala> addMany("sum = ")
sum = 0

scala> addMany("sum = ", Array(1, 2, 3))
<console>:13: error: type mismatch;
 found   : Array[Int]
 required: Int
       addMany("sum = ", Array(1, 2, 3))
                              ^

scala> addMany("sum = ", Array(1, 2, 3): _*)
sum = 6

6. 柯里化

对大多数其他编程语言,函数只能有一个参数列表,但是列表中可以有若干个用逗号隔开的参数。但在 Scala 中,柯里化允许一个函数有任意个参数列表。柯里化一般与另一个语法结合使用:当参数列表里只有一个参数时,调用该参数时允许单个参数不使用圆括号包裹,可以改用花括号,这样在自定义类库时看上去会比较像内建控制,而不是自定义语法。

scala> def add(x: Int, y: Int, z: Int) = x + y + z
add: (x: Int, y: Int, z: Int)Int

scala> add(1, 2, 3)
res0: Int = 6

scala> def addCurry(x: Int)(y: Int)(z: Int) = x + y + z
addCurry: (x: Int)(y: Int)(z: Int)Int

scala> addCurry(1)(2) {3}
res1: Int = 6

7. 传名函数

Scala 在解析函数参数(Function arguments)时有两种方式:

  • 传值调用(call-by-value):先计算函数参数表达式的值,再应用到函数内部;
  • 传名调用(call-by-name):将未计算函数参数的表达式直接传到函数内部。

简单的说,传名调用每次调用计算一次参数表达式,传值调用计算表达式后再进入函数 ,只有参数的值参与函数调用。

无参函数进行传名调用,调用时将括号省略。实例如下:

object Test {
    
      

  var n = 15  

  def count: Int = {
    
      
	n -= 1
	n  
  }

  def callByName(x: => Int): Unit = {
    
      
    for(i <- 0 until 5)  
      println( x )  
  }  
  def callByName2(x: () => Int): Unit = {
    
      
    for(i <- 0 until 5)  
      println( x() )  
  }  
  def callByValue(x: Int): Unit = {
    
      
    for(i <- 0 until 5)  
      println( x )  
  }  

  def main(args: Array[String]) = {
    
      
	val count2 = count _
    callByName(count)  
	callByName2(count2)  
    callByValue(count)  
  }  
}  

以上代码执行输出为:

14
13
12
11
10
9
8
7
6
5
4
4
4
4
4

猜你喜欢

转载自blog.csdn.net/verse_monger/article/details/114269836