本文记录 scala
的一些比较 有意思的语法特性
提取器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import scala.util.Random
object CustomerID {
def apply(name: String) = s"$name--${Random.nextLong}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
|
apply
就相当于构造器,接受参数然后创建一个对象实例
unapply
接受一个实例对象,然后返回最初创建它所用的参数
翻编译看的话,就是两个 静态函数,下面是 CustomerID.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public static scala.Option<java.lang.String> unapply(java.lang.String);
descriptor: (Ljava/lang/String;)Lscala/Option;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field CustomerID$.MODULE$:LCustomerID$;
3: aload_0
4: invokevirtual #20 // Method CustomerID$.unapply:(Ljava/lang/String;)Lscala/Option;
7: areturn
Signature: #11 // (Ljava/lang/String;)Lscala/Option<Ljava/lang/String;>;
MethodParameters:
Name Flags
customerID final
public static java.lang.String apply(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field CustomerID$.MODULE$:LCustomerID$;
3: aload_0
4: invokevirtual #25 // Method CustomerID$.apply:(Ljava/lang/String;)Ljava/lang/String;
7: areturn
MethodParameters:
Name Flags
name final
|
下面是 CustomerID$.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
public java.lang.String apply(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: new #22 // class java/lang/StringBuilder
3: dup
4: ldc #23 // int 2
6: invokespecial #26 // Method java/lang/StringBuilder."<init>":(I)V
9: aload_1
10: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
13: ldc #32 // String --
15: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
18: getstatic #37 // Field scala/util/Random$.MODULE$:Lscala/util/Random$;
21: invokevirtual #41 // Method scala/util/Random$.nextLong:()J
24: invokevirtual #44 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
27: invokevirtual #48 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: areturn
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 this LCustomerID$;
0 31 1 name Ljava/lang/String;
MethodParameters:
Name Flags
name final
public scala.Option<java.lang.String> unapply(java.lang.String);
descriptor: (Ljava/lang/String;)Lscala/Option;
flags: ACC_PUBLIC
Code:
stack=7, locals=3, args_size=2
0: aload_1
1: ldc #32 // String --
3: invokevirtual #60 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
6: astore_2
7: new #7 // class scala/collection/mutable/ArrayOps$ofRef
10: dup
11: getstatic #65 // Field scala/Predef$.MODULE$:Lscala/Predef$;
14: new #7 // class scala/collection/mutable/ArrayOps$ofRef
17: dup
18: getstatic #65 // Field scala/Predef$.MODULE$:Lscala/Predef$;
21: aload_2
22: checkcast #67 // class "[Ljava/lang/Object;"
25: invokevirtual #71 // Method scala/Predef$.refArrayOps:([Ljava/lang/Object;)[Ljava/lang/Objec
t;
28: invokespecial #74 // Method scala/collection/mutable/ArrayOps$ofRef."<init>":([Ljava/lang/Ob
ject;)V
31: invokevirtual #78 // Method scala/collection/mutable/ArrayOps$ofRef.tail:()Ljava/lang/Object
;
34: checkcast #67 // class "[Ljava/lang/Object;"
37: invokevirtual #71 // Method scala/Predef$.refArrayOps:([Ljava/lang/Object;)[Ljava/lang/Objec
t;
40: invokespecial #74 // Method scala/collection/mutable/ArrayOps$ofRef."<init>":([Ljava/lang/Ob
ject;)V
43: invokevirtual #82 // Method scala/collection/mutable/ArrayOps$ofRef.nonEmpty:()Z
46: ifeq 79
49: new #84 // class scala/Some
52: dup
53: new #7 // class scala/collection/mutable/ArrayOps$ofRef
56: dup
57: getstatic #65 // Field scala/Predef$.MODULE$:Lscala/Predef$;
60: aload_2
61: checkcast #67 // class "[Ljava/lang/Object;"
64: invokevirtual #71 // Method scala/Predef$.refArrayOps:([Ljava/lang/Object;)[Ljava/lang/Objec
t;
67: invokespecial #74 // Method scala/collection/mutable/ArrayOps$ofRef."<init>":([Ljava/lang/Ob
ject;)V
70: invokevirtual #87 // Method scala/collection/mutable/ArrayOps$ofRef.head:()Ljava/lang/Object
;
73: invokespecial #90 // Method scala/Some."<init>":(Ljava/lang/Object;)V
76: goto 82
79: getstatic #95 // Field scala/None$.MODULE$:Lscala/None$;
82: areturn
|
模式匹配
1
2
3
4
5
6
7
8
9
10
|
class person(id:Integer, name:String) {
def f(plan: AnyVal): Unit = {
val res = plan match {
case a @ AppendDelta(r, d) if !a.isByName => "1111"
case o @ OverwriteDelta(r, d) if !o.isByName => "222"
case a @ AppendDelta(r, d) => "333"
case a:Aggregate => "444"
case _=> "555"
}
}
|
反编译后如下,对应的 JVM 层,就是一堆的 instanceof
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public void f(java.lang.Object);
descriptor: (Ljava/lang/Object;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=11, args_size=2
0: iconst_0
1: istore 4
3: aconst_null
4: astore 5
6: aload_1
7: astore 6
9: aload 6
11: instanceof #13 // class org/apache/spark/sql/catalyst/plans/logical/AppendData
14: ifeq 62
17: iconst_1
18: istore 4
20: aload 6
22: checkcast #13 // class org/apache/spark/sql/catalyst/plans/logical/AppendData
25: astore 5
27: getstatic #19 // Field org/apache/spark/sql/delta/AppendDelta$.MODULE$:Lorg/apache/spark
/sql/delta/AppendDelta$;
30: aload 5
32: invokevirtual #23 // Method org/apache/spark/sql/delta/AppendDelta$.unapply:(Lorg/apache/spa
rk/sql/catalyst/plans/logical/AppendData;)Lscala/Option;
35: astore 7
37: aload 7
39: invokevirtual #29 // Method scala/Option.isEmpty:()Z
42: ifne 59
45: aload 5
47: invokevirtual #32 // Method org/apache/spark/sql/catalyst/plans/logical/AppendData.isByName:
()Z
50: ifne 59
53: ldc #34 // String 1111
55: astore_2
56: goto 176
59: goto 65
62: goto 65
65: aload 6
67: instanceof #36 // class org/apache/spark/sql/catalyst/plans/logical/OverwriteByExpression
|
高阶函数
多参数列表(柯里化)
类型上界和下界
隐式转换
泛类型
单例对象
一些语法特性
函数柯里化表示
内部函数
比如说,有这么一个类:
1
2
3
4
5
6
7
8
|
class gg() {
def x(i: Int): Unit = {
def inner_haha(a:String, b:String, c:String) = {
println("i -> " + i)
}
inner_haha("","","")
}
}
|
对于 JVM 字节码来说,是没法表示内嵌函数的,那么通过 dump 字节码看下结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public void x(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: ldc #13 // String
2: ldc #13 // String
4: ldc #13 // String
6: iload_1
7: invokestatic #17 // Method inner_haha$1:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Str
ing;I)V
10: return
private static final void inner_haha$1(java.lang.String, java.lang.String, java.lang.String, int);
descriptor: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
Code:
stack=4, locals=4, args_size=4
0: getstatic #30 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: new #32 // class java/lang/StringBuilder
6: dup
7: ldc #33 // int 5
9: invokespecial #36 // Method java/lang/StringBuilder."<init>":(I)V
12: ldc #38 // String i ->
14: invokevirtual #42 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
17: iload_3
18: invokevirtual #45 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
21: invokevirtual #49 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: invokevirtual #53 // Method scala/Predef$.println:(Ljava/lang/Object;)V
27: return
|
从字节码看, 是将 内部函数,变成了一个普通的 私有静态函数,同时给这个函数的参数列表最后,增加了一个int
当调用 inner_haha("","","") 时候,在 JVM 运行时看来,是调用 inner_haha("","","", i)