modify
This commit is contained in:
		| @@ -170,7 +170,7 @@ TODO | |||||||
| 7. [常用集合类型之——Map & Tuple](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala映射和元组.md) | 7. [常用集合类型之——Map & Tuple](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala映射和元组.md) | ||||||
| 8. [类和对象](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类和对象.md) | 8. [类和对象](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类和对象.md) | ||||||
| 9. [继承和特质](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala继承和特质.md) | 9. [继承和特质](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala继承和特质.md) | ||||||
| 10. [函数和闭包](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala函数和闭包.md) | 10. [函数 & 闭包 & 柯里化](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala函数和闭包.md) | ||||||
| 11. [模式匹配](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala模式匹配.md) | 11. [模式匹配](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala模式匹配.md) | ||||||
| 12. [类型参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类型参数.md) | 12. [类型参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类型参数.md) | ||||||
| 13. [隐式转换和隐式参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala隐式转换和隐式参数.md) | 13. [隐式转换和隐式参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala隐式转换和隐式参数.md) | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ | |||||||
|  |  | ||||||
| ### 1.1 函数与方法 | ### 1.1 函数与方法 | ||||||
|  |  | ||||||
| 在Scala中,函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数。 | Scala中函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 定义方法 | // 定义方法 | ||||||
| @@ -32,7 +32,7 @@ println(multi1(3)) //输出 9 | |||||||
| println(multi2(3)) //输出 9 | println(multi2(3)) //输出 9 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 其实对于定义函数,使用val和def并没有区别,你也可以使用`def`定义函数: | 也可以使用`def`定义函数: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| def multi3 = (x: Int) => {x * x} | def multi3 = (x: Int) => {x * x} | ||||||
| @@ -52,14 +52,14 @@ multi2: Int => Int = $$Lambda$1092/594363215@1dd1a777 | |||||||
| scala> def multi3 = (x: Int) => {x * x} | scala> def multi3 = (x: Int) => {x * x} | ||||||
| multi3: Int => Int | multi3: Int => Int | ||||||
|  |  | ||||||
| // 如果有多个参数,则类型(参数类型,参数类型 ...)=>返回值类型 | // 如果有多个参数,则类型为:(参数类型,参数类型 ...)=>返回值类型 | ||||||
| scala> val multi4 = (x: Int,name: String) => {name + x * x } | scala> val multi4 = (x: Int,name: String) => {name + x * x } | ||||||
| multi4: (Int, String) => String = $$Lambda$1093/1039732747@2eb4fe7 | multi4: (Int, String) => String = $$Lambda$1093/1039732747@2eb4fe7 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### 1.3 一等公民&匿名函数 | ### 1.3 一等公民&匿名函数 | ||||||
|  |  | ||||||
| 在Scala中函数是一等公民,这意味着不仅可以定义函数并调用它们,还可以用匿名的字面量来编写函数并将它们作为值进行传递: | 在Scala中函数是一等公民,这意味着不仅可以定义函数并调用它们,还可以将它们作为值进行传递: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| import scala.math.ceil | import scala.math.ceil | ||||||
| @@ -93,7 +93,7 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| #### 1. 可变长度参数列表 | #### 1. 可变长度参数列表 | ||||||
|  |  | ||||||
| 在Java中如果你想要传递可变长度的参数列表,则需要使用`String ...args`这种语法,Scala中等效的语法为`args: String*`。 | 在Java中如果你想要传递可变长度的参数,需要使用`String ...args`这种形式,Scala中等效的表达为`args: String*`。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
| @@ -110,7 +110,7 @@ flink | |||||||
|  |  | ||||||
| #### 2. 传递具名参数 | #### 2. 传递具名参数 | ||||||
|  |  | ||||||
| 向函数传递参数时候可以指定具体的名称。 | 向函数传递参数时候可以指定具体的参数名。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
| @@ -127,7 +127,7 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| #### 3. 默认值参数 | #### 3. 默认值参数 | ||||||
|  |  | ||||||
| 可以为函数的参数指定默认值。 | 在定义函数时,可以为参数指定默认值。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
| @@ -163,7 +163,7 @@ val addMore = (x: Int) => x + more | |||||||
| 这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着: | 这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着: | ||||||
|  |  | ||||||
| + 闭包外部对自由变量的修改,在闭包内部是可见的; | + 闭包外部对自由变量的修改,在闭包内部是可见的; | ||||||
| + 闭包内部对自由变量的修改,在闭包外部也是可见的; | + 闭包内部对自由变量的修改,在闭包外部也是可见的。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 声明more变量 | // 声明more变量 | ||||||
| @@ -239,7 +239,7 @@ object ScalaApp extends App { | |||||||
|     x * x |     x * x | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // 2.定义高阶函数: 第一个参数是类型为Int => Int的函数,第二个参数为Int类型的值 |   // 2.定义高阶函数: 第一个参数是类型为Int => Int的函数 | ||||||
|   def multi(fun: Int => Int, x: Int) = { |   def multi(fun: Int => Int, x: Int) = { | ||||||
|     fun(x) * 100 |     fun(x) * 100 | ||||||
|   } |   } | ||||||
| @@ -267,8 +267,8 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| 这里当你调用curriedSum时候,实际上是连着做了两次传统的函数调用,实际执行的柯里化过程如下: | 这里当你调用curriedSum时候,实际上是连着做了两次传统的函数调用,实际执行的柯里化过程如下: | ||||||
|  |  | ||||||
| + 第一次调用接收一个名为x的int参数,返回一个用于第二次调用的函数,假设x为2,则返回函数`2+y`; | + 第一次调用接收一个名为`x`的Int型参数,返回一个用于第二次调用的函数,假设`x`为2,则返回函数`2+y`; | ||||||
| + 返回的函数接收Int参数y,并计算并返回值`2+3`的值。 | + 返回的函数接收参数`y`,并计算并返回值`2+3`的值。 | ||||||
|  |  | ||||||
| 想要获得柯里化的中间返回的函数其实也比较简单: | 想要获得柯里化的中间返回的函数其实也比较简单: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -32,8 +32,8 @@ scala> list(1) = "hive" | |||||||
|  |  | ||||||
| Scala中List具有以下两个特性: | Scala中List具有以下两个特性: | ||||||
|  |  | ||||||
| + 同构(homogeneous):同一个List中的所有元素都必须是相同的类型; | + **同构(homogeneous)**:同一个List中的所有元素都必须是相同的类型; | ||||||
| + 协变(covariant):如果S是T的子类型,那么`List[S]`就是`List[T]`的子类型,例如`List[String]`是`List[Object]`的子类型。 | + **协变(covariant)**:如果S是T的子类型,那么`List[S]`就是`List[T]`的子类型,例如`List[String]`是`List[Object]`的子类型。 | ||||||
|  |  | ||||||
| 需要特别说明的是空列表的类型为`List[Nothing]`: | 需要特别说明的是空列表的类型为`List[Nothing]`: | ||||||
|  |  | ||||||
| @@ -127,9 +127,9 @@ res2: scala.collection.immutable.Range = Range(0, 1, 2) | |||||||
|  |  | ||||||
| ### 5.3 take & drop & splitAt | ### 5.3 take & drop & splitAt | ||||||
|  |  | ||||||
| - take:获取前n个元素; | - **take**:获取前n个元素; | ||||||
| - drop:删除前n个元素; | - **drop**:删除前n个元素; | ||||||
| - splitAt:从第几个位置开始拆分。 | - **splitAt**:从第几个位置开始拆分。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| scala> list take 2 | scala> list take 2 | ||||||
| @@ -168,14 +168,14 @@ res7: (List[String], List[Int]) = (List(hadoop, spark, storm),List(10, 20, 30)) | |||||||
|  |  | ||||||
| ### 5.6 toString & mkString | ### 5.6 toString & mkString | ||||||
|  |  | ||||||
| toString 返回 list的字符串表现形式。 | toString 返回List的字符串表现形式。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| scala> list.toString | scala> list.toString | ||||||
| res8: String = List(hadoop, spark, storm) | res8: String = List(hadoop, spark, storm) | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 如果想改变list的字符串表现形式,可以使用mkString,mkString有三个重载方法: | 如果想改变List的字符串表现形式,可以使用mkString。mkString有三个重载方法,方法定义如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // start:前缀  sep:分隔符  end:后缀 | // start:前缀  sep:分隔符  end:后缀 | ||||||
| @@ -335,7 +335,7 @@ res27: (List[Int], List[Int]) = (List(1, 2, 3),List(-4, 5)) | |||||||
|  |  | ||||||
| ### 6.3 列表检查:forall & exists | ### 6.3 列表检查:forall & exists | ||||||
|  |  | ||||||
| forall检查List中所有元素,如果所有元素都满足条件,则返回true; | forall检查List中所有元素,如果所有元素都满足条件,则返回true。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| scala> List(1, 2, 3, -4, 5) forall ( _ > 0 ) | scala> List(1, 2, 3, -4, 5) forall ( _ > 0 ) | ||||||
|   | |||||||
| @@ -98,18 +98,18 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| ### 1.4 提取器 | ### 1.4 提取器 | ||||||
|  |  | ||||||
| 数组、列表和元组能使用模式匹配,都是依靠提取器(extractor)机制,它们伴生对象中定义unapply或unapplySeq方法: | 数组、列表和元组能使用模式匹配,都是依靠提取器(extractor)机制,它们伴生对象中定义了`unapply`或`unapplySeq`方法: | ||||||
|  |  | ||||||
| + unapply方法用于提取固定数量的对象; | + **unapply**:用于提取固定数量的对象; | ||||||
| + unapplySeq用于提取一个序列; | + **unapplySeq**:用于提取一个序列; | ||||||
|  |  | ||||||
| 以下是`Array.scala`类源码中定义的`unapplySeq`方法: | 这里以数组为例,`Array.scala`定义了`unapplySeq`方法: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| def unapplySeq[T](x : scala.Array[T]) : scala.Option[scala.IndexedSeq[T]] = { /* compiled code */ } | def unapplySeq[T](x : scala.Array[T]) : scala.Option[scala.IndexedSeq[T]] = { /* compiled code */ } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| `unapplySeq`返回一个序列值,即数组中的值,以和模式匹配case语句中的表达式进行对应位置的值匹配。 | `unapplySeq`返回一个序列,包含数组中的所有值,这样在模式匹配时,才能知道对应位置上的值。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -138,7 +138,7 @@ case class Student(name: String, age: Int) extends Person {} | |||||||
|  |  | ||||||
| - 构造器中每个参数都默认为`val`; | - 构造器中每个参数都默认为`val`; | ||||||
| - 自动地生成`equals, hashCode, toString, copy`等方法; | - 自动地生成`equals, hashCode, toString, copy`等方法; | ||||||
| - 伴生对象中自动生成`apply`方法,使得不用new关键字就能构造出相应的对象; | - 伴生对象中自动生成`apply`方法,使得可以不用new关键字就能构造出相应的对象; | ||||||
| - 伴生对象中自动生成`unapply`方法,以支持模式匹配。 | - 伴生对象中自动生成`unapply`方法,以支持模式匹配。 | ||||||
|  |  | ||||||
| 除了上面的特征外,样例类和其他类相同,可以任意添加方法和字段,扩展它们。 | 除了上面的特征外,样例类和其他类相同,可以任意添加方法和字段,扩展它们。 | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ | |||||||
|  |  | ||||||
| ## 一、初识类和对象 | ## 一、初识类和对象 | ||||||
|  |  | ||||||
| Scala中的类与Java中的类具有非常多的相似性,这里为了有个直观上的印象,首先给出一个类的示例。 | Scala的类与Java的类具有非常多的相似性,示例如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 1. 在scala中,类不需要用public声明,所有的类都具有公共的可见性 | // 1. 在scala中,类不需要用public声明,所有的类都具有公共的可见性 | ||||||
| @@ -26,11 +26,11 @@ class Person { | |||||||
|   // 2. 声明私有变量,用var修饰的变量默认拥有getter/setter属性 |   // 2. 声明私有变量,用var修饰的变量默认拥有getter/setter属性 | ||||||
|   private var age = 0 |   private var age = 0 | ||||||
|  |  | ||||||
|   // 3.如果声明的变量不需要进行初始赋值,此时scala无法进行类型推荐,需要显式指明类型 |   // 3.如果声明的变量不需要进行初始赋值,此时Scala就无法进行类型推断,所以需要显式指明类型 | ||||||
|   private var name: String = _ |   private var name: String = _ | ||||||
|  |  | ||||||
|  |  | ||||||
|   // 4. 定义方法,应该指明传参类型和返回值的类型 |   // 4. 定义方法,应指明传参类型。返回值类型不是必须的,Scala可以自动推断出来,但是为了方便调用者,建议指明 | ||||||
|   def growUp(step: Int): Unit = { |   def growUp(step: Int): Unit = { | ||||||
|     age += step |     age += step | ||||||
|   } |   } | ||||||
| @@ -58,7 +58,7 @@ class Person { | |||||||
| object Person { | object Person { | ||||||
|  |  | ||||||
|   def main(args: Array[String]): Unit = { |   def main(args: Array[String]): Unit = { | ||||||
|     // 8.创建类的实例对象 |     // 8.创建类的实例 | ||||||
|     val counter = new Person() |     val counter = new Person() | ||||||
|     // 9.用var修饰的变量默认拥有getter/setter属性,可以直接对其进行赋值 |     // 9.用var修饰的变量默认拥有getter/setter属性,可以直接对其进行赋值 | ||||||
|     counter.age = 12 |     counter.age = 12 | ||||||
| @@ -120,8 +120,8 @@ object Person { | |||||||
| > | > | ||||||
| > ```scala | > ```scala | ||||||
| > class Person { | > class Person { | ||||||
| >   var name = "" | > var name = "" | ||||||
| >   private var age = "" | > private var age = "" | ||||||
| > } | > } | ||||||
| > ``` | > ``` | ||||||
| > | > | ||||||
| @@ -132,21 +132,21 @@ object Person { | |||||||
| > > javap -private Person | > > javap -private Person | ||||||
| > ``` | > ``` | ||||||
| > | > | ||||||
| > 编译结果如下,从编译结果可以看到实际的get和set的方法名,同时也验证了成员变量默认的可见性为public。 | > 编译结果如下,从编译结果可以看到实际的get和set的方法名(因为JVM不允许在方法名中出现=,所以它被翻译成$eq),同时也验证了成员变量默认的可见性为public。 | ||||||
| > | > | ||||||
| > ```java | > ```java | ||||||
| > Compiled from "Person.scala" | > Compiled from "Person.scala" | ||||||
| > public class Person { | > public class Person { | ||||||
| >   private java.lang.String name; | > private java.lang.String name; | ||||||
| >   private java.lang.String age; | > private java.lang.String age; | ||||||
| >   | >   | ||||||
| >   public java.lang.String name(); | > public java.lang.String name(); | ||||||
| >   public void name_$eq(java.lang.String); | > public void name_$eq(java.lang.String); | ||||||
| >   | >   | ||||||
| >   private java.lang.String age(); | > private java.lang.String age(); | ||||||
| >   private void age_$eq(java.lang.String); | > private void age_$eq(java.lang.String); | ||||||
| >   | >   | ||||||
| >   public Person(); | > public Person(); | ||||||
| > } | > } | ||||||
| > ``` | > ``` | ||||||
|  |  | ||||||
| @@ -172,7 +172,7 @@ object Person { | |||||||
|  |  | ||||||
| ### 2.4 主构造器 | ### 2.4 主构造器 | ||||||
|  |  | ||||||
| 和Java不同的是,Scala类的主构造器直接写在类名后面,同时需要注意以下两点: | 和Java不同的是,Scala类的主构造器直接写在类名后面,但注意以下两点: | ||||||
|  |  | ||||||
| + 主构造器传入的参数默认就是val类型的,即不可变,你没有办法在内部改变传参; | + 主构造器传入的参数默认就是val类型的,即不可变,你没有办法在内部改变传参; | ||||||
| + 写在主构造器中的代码块会在类初始化的时候被执行,功能类似于Java的静态代码块`static{}` | + 写在主构造器中的代码块会在类初始化的时候被执行,功能类似于Java的静态代码块`static{}` | ||||||
| @@ -206,7 +206,7 @@ heibaiying:20 | |||||||
|  |  | ||||||
| 辅助构造器有两点硬性要求: | 辅助构造器有两点硬性要求: | ||||||
|  |  | ||||||
| + 辅助构造器的名称必须为this; | + 辅助构造器的名称必须为this; | ||||||
| + 每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。 | + 每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| @@ -236,7 +236,7 @@ object Person { | |||||||
|  |  | ||||||
| ### 2.6 方法传参不可变 | ### 2.6 方法传参不可变 | ||||||
|  |  | ||||||
| 在Scala中,方法传参默认是val类型,即不可变,这意味着你在方法体内部不能改变传入的参数。这和scala的设计理念有关,Scala遵循函数式编程理念,强调方法不应该有副作用。 | 在Scala中,方法传参默认是val类型,即不可变,这意味着你在方法体内部不能改变传入的参数。这和Scala的设计理念有关,Scala遵循函数式编程理念,强调方法不应该有副作用。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| class Person() { | class Person() { | ||||||
| @@ -378,16 +378,19 @@ object Color extends Enumeration { | |||||||
| 使用枚举类: | 使用枚举类: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
|  | // 1.使用类型别名导入枚举类 | ||||||
|  | import com.heibaiying.Color.Color | ||||||
|  |  | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
|  |  | ||||||
|   // 1.使用枚举类型,这种情况下需要导入枚举类,在枚举类中定义的类型别名就有用了 |   // 2.使用枚举类型,这种情况下需要导入枚举类 | ||||||
|   def printColor(color: Color): Unit = { |   def printColor(color: Color): Unit = { | ||||||
|     println(color.toString) |     println(color.toString) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // 2.判断传入值和枚举值是否相等 |   // 3.判断传入值和枚举值是否相等 | ||||||
|   println(Color.YELLOW.toString == "yellow") |   println(Color.YELLOW.toString == "yellow") | ||||||
|   // 3.遍历枚举类和值 |   // 4.遍历枚举类和值 | ||||||
|   for (c <- Color.values) println(c.id + ":" + c.toString) |   for (c <- Color.values) println(c.id + ":" + c.toString) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -60,9 +60,7 @@ object Utils { | |||||||
|  |  | ||||||
| ### 2.1 类型上界限定 | ### 2.1 类型上界限定 | ||||||
|  |  | ||||||
| Scala和Java一样,对于对象之间进行大小比较,要求被比较的对象实现`java.lang.Comparable`接口。 | Scala和Java一样,对于对象之间进行大小比较,要求被比较的对象实现`java.lang.Comparable`接口。所以如果想对泛型进行比较,需要限定类型上界为`java.lang.Comparable`,语法为` S <: T`,代表类型S是类型T的子类或其本身。示例如下: | ||||||
|  |  | ||||||
| 所以如果想对泛型进行比较,需要限定类型上界为`java.lang.Comparable`,语法为` S <: T`,代表类型S是类型T的子类或其本身。示例如下: |  | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 使用 <: 符号,限定T必须是Comparable[T]的子类型 | // 使用 <: 符号,限定T必须是Comparable[T]的子类型 | ||||||
| @@ -126,7 +124,7 @@ trait Ordered[A] extends Any with java.lang.Comparable[A] { | |||||||
|  |  | ||||||
| <div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-richInt.png"/> </div> | <div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-richInt.png"/> </div> | ||||||
|  |  | ||||||
| 要想解决传入数值无法进行比较的问题,可以使用视图界定。语法为`T <% U`,代表T能够通过隐式转换转为U,即允许Int型参数在无法进行比较的时候转换为RichInt类型。示例如下: | 要想解决传入数值无法进行比较的问题,可以使用视图界定。语法为`T <% U`,代表T能够通过隐式转换转为U,即允许Int型参数在无法进行比较的时候转换为RichInt类型。示例如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 视图界定符号 <% | // 视图界定符号 <% | ||||||
| @@ -147,7 +145,7 @@ class Pair[T <% Comparable[T]](val first: T, val second: T) { | |||||||
|  |  | ||||||
| ### 2.3 类型约束 | ### 2.3 类型约束 | ||||||
|  |  | ||||||
| 如果你用的Scala是2.11+,会发现IDEA会提示视图界定已被标识为废弃。官方推荐使用类型约束(type constraint)来实现同样的功能,其本质是使用隐式参数进行隐式转换,示例如下: | 如果你用的Scala是2.11+,会发现视图界定已被标识为废弃。官方推荐使用类型约束(type constraint)来实现同样的功能,其本质是使用隐式参数进行隐式转换,示例如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
|  // 1.使用隐式参数隐式转换为Comparable[T] |  // 1.使用隐式参数隐式转换为Comparable[T] | ||||||
| @@ -224,7 +222,7 @@ object ScalaApp extends App { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Scala针对这个问题,提供了ClassTag上下文界定,即把泛型的信息存储在ClassTag中,这样在运行阶段需要时,只需要从中进行获取即可。其语法为`T : ClassTag`,示例如下: | Scala针对这个问题,提供了ClassTag上下文界定,即把泛型的信息存储在ClassTag中,这样在运行阶段需要时,只需要从ClassTag中进行获取即可。其语法为`T : ClassTag`,示例如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| import scala.reflect._ | import scala.reflect._ | ||||||
| @@ -309,7 +307,7 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| ### 3.1 Comparable | ### 3.1 Comparable | ||||||
|  |  | ||||||
| ```scala | ```java | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| // 实现Comparable接口 | // 实现Comparable接口 | ||||||
| public class Person implements Comparable<Person> { | public class Person implements Comparable<Person> { | ||||||
| @@ -342,7 +340,7 @@ ying:77 | |||||||
|  |  | ||||||
| ### 3.2 Comparator | ### 3.2 Comparator | ||||||
|  |  | ||||||
| ```scala | ```java | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Comparator; | import java.util.Comparator; | ||||||
|  |  | ||||||
| @@ -358,7 +356,7 @@ public class Person { | |||||||
|     public static void main(String[] args) { |     public static void main(String[] args) { | ||||||
|         Person[] peoples= {new Person("hei", 66), new Person("bai", 55), new Person("ying", 77)}; |         Person[] peoples= {new Person("hei", 66), new Person("bai", 55), new Person("ying", 77)}; | ||||||
|         // 这里为了直观直接使用匿名内部类,实现Comparator接口 |         // 这里为了直观直接使用匿名内部类,实现Comparator接口 | ||||||
|          //如果是Java8你也可以写成Arrays.sort(peoples, Comparator.comparingInt(o -> o.age)); |         //如果是Java8你也可以写成Arrays.sort(peoples, Comparator.comparingInt(o -> o.age)); | ||||||
|         Arrays.sort(peoples, new Comparator<Person>() { |         Arrays.sort(peoples, new Comparator<Person>() { | ||||||
|             @Override |             @Override | ||||||
|             public int compare(Person o1, Person o2) { |             public int compare(Person o1, Person o2) { | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ Scala中继承关系如下图: | |||||||
|  |  | ||||||
| ### 1.2 extends & override | ### 1.2 extends & override | ||||||
|  |  | ||||||
| Scala的集成机制和Java有很多相似之处,比如都使用`extends`关键字表示继承,都使用`override`关键字表示重写父类的方法或成员变量。下面给出一个Scala继承的示例: | Scala的集成机制和Java有很多相似之处,比如都使用`extends`关键字表示继承,都使用`override`关键字表示重写父类的方法或成员变量。示例如下: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| //父类 | //父类 | ||||||
| @@ -102,7 +102,7 @@ class Employee(name:String,age:Int,salary:Double) extends Person(name:String,age | |||||||
|  |  | ||||||
| ### 1.4 类型检查和转换 | ### 1.4 类型检查和转换 | ||||||
|  |  | ||||||
| 想要实现类检查可以使用`isInstanceOf`,判断一个实例是否来源于某个类或者其子类,如果是,则可以使用`asInstanceOf`进行强制类型转换。 | 想要实现类检查可以使用`isInstanceOf`,判断一个实例是否来源于某个类或者其子类,如果是,则可以使用`asInstanceOf`进行强制类型转换。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
| @@ -208,7 +208,7 @@ class Employee extends { | |||||||
|  |  | ||||||
| 但是这种语法也有其限制:你只能在上面代码块中重写已有的变量,而不能定义新的变量和方法,定义新的变量和方法只能写在下面代码块中。 | 但是这种语法也有其限制:你只能在上面代码块中重写已有的变量,而不能定义新的变量和方法,定义新的变量和方法只能写在下面代码块中。 | ||||||
|  |  | ||||||
| >**注意事项**:不仅是类的继承存在这个问题,后文介绍的特质(trait)的继承也存在这个问题,也同样可以通过提前定义来解决。即便可以通过多种方法解决该问题,但还是建议合理设计继承以规避此类问题。 | >**注意事项**:类的继承和下文特质(trait)的继承都存在这个问题,也同样可以通过提前定义来解决。虽然如此,但还是建议合理设计以规避该类问题。 | ||||||
|  |  | ||||||
| <br/> | <br/> | ||||||
|  |  | ||||||
| @@ -270,7 +270,7 @@ trait Logger { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 想要使用特质,需要使用`extends`关键字,而不是`implements`关键字,如果想要添加多个特质,可以使用`with`关键字。 | 想要使用特质,需要使用`extends`关键字,而不是`implements`关键字,如果想要添加多个特质,可以使用`with`关键字。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 1.使用extends关键字,而不是implements,如果想要添加多个特质,可以使用with关键字 | // 1.使用extends关键字,而不是implements,如果想要添加多个特质,可以使用with关键字 | ||||||
| @@ -310,7 +310,7 @@ class InfoLogger extends Logger { | |||||||
|  |  | ||||||
| ### 3.3 带有特质的对象 | ### 3.3 带有特质的对象 | ||||||
|  |  | ||||||
| Scala支持在类定义的时混入`父类trait`,而在类实例化为具体对象的时候指明其实际使用的`子类trait`。下面给出一个示例: | Scala支持在类定义的时混入`父类trait`,而在类实例化为具体对象的时候指明其实际使用的`子类trait`。示例如下: | ||||||
|  |  | ||||||
| <div align="center"> <img  src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala带有特质的对象.png"/> </div> | <div align="center"> <img  src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala带有特质的对象.png"/> </div> | ||||||
|  |  | ||||||
| @@ -388,9 +388,9 @@ object ScalaApp extends App { | |||||||
| class Employee extends Person with InfoLogger with ErrorLogger {...} | class Employee extends Person with InfoLogger with ErrorLogger {...} | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 1. 超类首先被构造(Person构造器执行); | 1. 超类首先被构造,即Person的构造器首先被执行; | ||||||
| 2. 特质的构造器在超类构造器之前,在类构造器之后;特质由左到右被构造;每个特质中,父特质首先被构造; | 2. 特质的构造器在超类构造器之前,在类构造器之后;特质由左到右被构造;每个特质中,父特质首先被构造; | ||||||
|    + Logger构造器执行(Logger是InfoLogger的父类); |    + Logger构造器执行(Logger是InfoLogger的父类); | ||||||
|    + InfoLogger构造器执行; |    + InfoLogger构造器执行; | ||||||
|    + ErrorLogger构造器执行; |    + ErrorLogger构造器执行; | ||||||
| 3. 所有超类和特质构造完毕,子类才会被构造。 | 3. 所有超类和特质构造完毕,子类才会被构造。 | ||||||
|   | |||||||
| @@ -129,7 +129,7 @@ This is Class B | |||||||
|  |  | ||||||
| 上面我们使用的方法相当于直接定义在执行代码的作用域中,下面分别给出其他两种定义的代码示例: | 上面我们使用的方法相当于直接定义在执行代码的作用域中,下面分别给出其他两种定义的代码示例: | ||||||
|  |  | ||||||
| 定义在原类型的伴生对象中: | **定义在原类型的伴生对象中**: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| class Person(val name: String) | class Person(val name: String) | ||||||
| @@ -154,7 +154,7 @@ object ScalaApp extends App { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 定义在一个公共的对象中: | **定义在一个公共的对象中**: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object Convert { | object Convert { | ||||||
| @@ -167,12 +167,11 @@ object Convert { | |||||||
| import com.heibaiying.Convert._ | import com.heibaiying.Convert._ | ||||||
|  |  | ||||||
| object ScalaApp extends App { | object ScalaApp extends App { | ||||||
|   // 这样普通人也能举起雷神之锤 |  | ||||||
|   new Person("普通人").hammer() |   new Person("普通人").hammer() | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| > 注:Scala中隐式转换函数大部分定义在`Predef.scala`中,你可以打开源文件查看,也可以在Scala交互式命令行中采用`:implicit -v`查看全部隐式转换函数。 | > 注:Scala自身的隐式转换函数大部分定义在`Predef.scala`中,你可以打开源文件查看,也可以在Scala交互式命令行中采用`:implicit -v`查看全部隐式转换函数。 | ||||||
|  |  | ||||||
| <br/> | <br/> | ||||||
|  |  | ||||||
| @@ -180,7 +179,7 @@ object ScalaApp extends App { | |||||||
|  |  | ||||||
| ### 2.1 使用隐式参数 | ### 2.1 使用隐式参数 | ||||||
|  |  | ||||||
| 函数或方法可以带有一个标记为`implicit`的参数列表,这种情况下,编译器将会查找默认值,提供给函数调用。 | 在定义函数或方法时可以使用标记为`implicit`的参数,这种情况下,编译器将会查找默认值,提供给函数调用。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| // 定义分隔符类 | // 定义分隔符类 | ||||||
| @@ -204,7 +203,7 @@ object ScalaApp extends App { | |||||||
| 1.我们上面定义`formatted`函数的时候使用了柯里化,如果你不使用柯里化表达式,按照通常习惯只有下面两种写法: | 1.我们上面定义`formatted`函数的时候使用了柯里化,如果你不使用柯里化表达式,按照通常习惯只有下面两种写法: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| //这种写法没有语法错误,但是无法通过编译 | // 这种写法没有语法错误,但是无法通过编译 | ||||||
| def formatted(implicit context: String, deli: Delimiters): Unit = { | def formatted(implicit context: String, deli: Delimiters): Unit = { | ||||||
|   println(deli.left + context + deli.right) |   println(deli.left + context + deli.right) | ||||||
| }  | }  | ||||||
| @@ -243,7 +242,7 @@ formatted("this is context") | |||||||
|  |  | ||||||
| 我们上面示例程序相当于直接定义执行代码的上下文作用域中,下面给出其他两种方式的示例: | 我们上面示例程序相当于直接定义执行代码的上下文作用域中,下面给出其他两种方式的示例: | ||||||
|  |  | ||||||
| 定义在隐式参数对应类的伴生对象中; | **定义在隐式参数对应类的伴生对象中**; | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| class Delimiters(val left: String, val right: String) | class Delimiters(val left: String, val right: String) | ||||||
| @@ -264,7 +263,7 @@ object ScalaApp extends App { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 统一定义在一个文件中,在使用时候导入: | **统一定义在一个文件中,在使用时候导入**: | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object Convert { | object Convert { | ||||||
| @@ -292,9 +291,7 @@ object ScalaApp extends App { | |||||||
| def smaller[T] (a: T, b: T) = if (a < b) a else b | def smaller[T] (a: T, b: T) = if (a < b) a else b | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 在Scala中如果定义了一个如上所示的比较对象大小的泛型方法,你会发现无法通过编译。对于对象之间进行大小比较,Scala和Java一样,都要求被比较的对象需要实现java.lang.Comparable接口。 | 在Scala中如果定义了一个如上所示的比较对象大小的泛型方法,你会发现无法通过编译。对于对象之间进行大小比较,Scala和Java一样,都要求被比较的对象需要实现java.lang.Comparable接口。在Scala中,直接继承Java中Comparable接口的是特质Ordered,它在继承compareTo方法的基础上,额外定义了关系符方法,源码如下: | ||||||
|  |  | ||||||
| 在Scala中,直接继承Java中Comparable接口的是特质Ordered,它在继承compareTo方法的基础上,额外定义了关系符方法,源码如下: |  | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| trait Ordered[A] extends Any with java.lang.Comparable[A] { | trait Ordered[A] extends Any with java.lang.Comparable[A] { | ||||||
| @@ -336,7 +333,7 @@ object Pair extends App { | |||||||
|  |  | ||||||
| #### 2. 利用隐式参数进行隐式转换 | #### 2. 利用隐式参数进行隐式转换 | ||||||
|  |  | ||||||
| 在Scala2.11+后,视图界定被标识为废弃,官方推荐使用类型限定来解决上面的问题,本质上就是使用隐式参数进行隐式转换。 | Scala2.11+后,视图界定被标识为废弃,官方推荐使用类型限定来解决上面的问题,本质上就是使用隐式参数进行隐式转换。 | ||||||
|  |  | ||||||
| ```scala | ```scala | ||||||
| object Pair extends App { | object Pair extends App { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user