diff --git a/README.md b/README.md index 4cad8ba..d760e2d 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ TODO 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) 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) 12. [类型参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类型参数.md) 13. [隐式转换和隐式参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala隐式转换和隐式参数.md) diff --git a/notes/Scala函数和闭包.md b/notes/Scala函数和闭包.md index 5f0b5ec..f492a36 100644 --- a/notes/Scala函数和闭包.md +++ b/notes/Scala函数和闭包.md @@ -20,7 +20,7 @@ ### 1.1 函数与方法 -在Scala中,函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数。 +Scala中函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数。 ```scala // 定义方法 @@ -32,7 +32,7 @@ println(multi1(3)) //输出 9 println(multi2(3)) //输出 9 ``` -其实对于定义函数,使用val和def并没有区别,你也可以使用`def`定义函数: +也可以使用`def`定义函数: ```scala def multi3 = (x: Int) => {x * x} @@ -52,14 +52,14 @@ multi2: Int => Int = $$Lambda$1092/594363215@1dd1a777 scala> def multi3 = (x: Int) => {x * x} multi3: Int => Int -// 如果有多个参数,则类型(参数类型,参数类型 ...)=>返回值类型 +// 如果有多个参数,则类型为:(参数类型,参数类型 ...)=>返回值类型 scala> val multi4 = (x: Int,name: String) => {name + x * x } multi4: (Int, String) => String = $$Lambda$1093/1039732747@2eb4fe7 ``` ### 1.3 一等公民&匿名函数 -在Scala中函数是一等公民,这意味着不仅可以定义函数并调用它们,还可以用匿名的字面量来编写函数并将它们作为值进行传递: +在Scala中函数是一等公民,这意味着不仅可以定义函数并调用它们,还可以将它们作为值进行传递: ```scala import scala.math.ceil @@ -93,7 +93,7 @@ object ScalaApp extends App { #### 1. 可变长度参数列表 -在Java中如果你想要传递可变长度的参数列表,则需要使用`String ...args`这种语法,Scala中等效的语法为`args: String*`。 +在Java中如果你想要传递可变长度的参数,需要使用`String ...args`这种形式,Scala中等效的表达为`args: String*`。 ```scala object ScalaApp extends App { @@ -110,7 +110,7 @@ flink #### 2. 传递具名参数 -向函数传递参数时候可以指定具体的名称。 +向函数传递参数时候可以指定具体的参数名。 ```scala object ScalaApp extends App { @@ -127,7 +127,7 @@ object ScalaApp extends App { #### 3. 默认值参数 -可以为函数的参数指定默认值。 +在定义函数时,可以为参数指定默认值。 ```scala object ScalaApp extends App { @@ -163,7 +163,7 @@ val addMore = (x: Int) => x + more 这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着: + 闭包外部对自由变量的修改,在闭包内部是可见的; -+ 闭包内部对自由变量的修改,在闭包外部也是可见的; ++ 闭包内部对自由变量的修改,在闭包外部也是可见的。 ```scala // 声明more变量 @@ -239,7 +239,7 @@ object ScalaApp extends App { x * x } - // 2.定义高阶函数: 第一个参数是类型为Int => Int的函数,第二个参数为Int类型的值 + // 2.定义高阶函数: 第一个参数是类型为Int => Int的函数 def multi(fun: Int => Int, x: Int) = { fun(x) * 100 } @@ -267,8 +267,8 @@ object ScalaApp extends App { 这里当你调用curriedSum时候,实际上是连着做了两次传统的函数调用,实际执行的柯里化过程如下: -+ 第一次调用接收一个名为x的int参数,返回一个用于第二次调用的函数,假设x为2,则返回函数`2+y`; -+ 返回的函数接收Int参数y,并计算并返回值`2+3`的值。 ++ 第一次调用接收一个名为`x`的Int型参数,返回一个用于第二次调用的函数,假设`x`为2,则返回函数`2+y`; ++ 返回的函数接收参数`y`,并计算并返回值`2+3`的值。 想要获得柯里化的中间返回的函数其实也比较简单: diff --git a/notes/Scala列表和集.md b/notes/Scala列表和集.md index 705c1af..e33ade7 100644 --- a/notes/Scala列表和集.md +++ b/notes/Scala列表和集.md @@ -32,8 +32,8 @@ scala> list(1) = "hive" Scala中List具有以下两个特性: -+ 同构(homogeneous):同一个List中的所有元素都必须是相同的类型; -+ 协变(covariant):如果S是T的子类型,那么`List[S]`就是`List[T]`的子类型,例如`List[String]`是`List[Object]`的子类型。 ++ **同构(homogeneous)**:同一个List中的所有元素都必须是相同的类型; ++ **协变(covariant)**:如果S是T的子类型,那么`List[S]`就是`List[T]`的子类型,例如`List[String]`是`List[Object]`的子类型。 需要特别说明的是空列表的类型为`List[Nothing]`: @@ -127,9 +127,9 @@ res2: scala.collection.immutable.Range = Range(0, 1, 2) ### 5.3 take & drop & splitAt -- take:获取前n个元素; -- drop:删除前n个元素; -- splitAt:从第几个位置开始拆分。 +- **take**:获取前n个元素; +- **drop**:删除前n个元素; +- **splitAt**:从第几个位置开始拆分。 ```scala 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 -toString 返回 list的字符串表现形式。 +toString 返回List的字符串表现形式。 ```scala scala> list.toString res8: String = List(hadoop, spark, storm) ``` -如果想改变list的字符串表现形式,可以使用mkString,mkString有三个重载方法: +如果想改变List的字符串表现形式,可以使用mkString。mkString有三个重载方法,方法定义如下: ```scala // start:前缀 sep:分隔符 end:后缀 @@ -335,7 +335,7 @@ res27: (List[Int], List[Int]) = (List(1, 2, 3),List(-4, 5)) ### 6.3 列表检查:forall & exists -forall检查List中所有元素,如果所有元素都满足条件,则返回true; +forall检查List中所有元素,如果所有元素都满足条件,则返回true。 ```scala scala> List(1, 2, 3, -4, 5) forall ( _ > 0 ) diff --git a/notes/Scala模式匹配.md b/notes/Scala模式匹配.md index f43951f..1b06f8c 100644 --- a/notes/Scala模式匹配.md +++ b/notes/Scala模式匹配.md @@ -98,18 +98,18 @@ object ScalaApp extends App { ### 1.4 提取器 -数组、列表和元组能使用模式匹配,都是依靠提取器(extractor)机制,它们伴生对象中定义unapply或unapplySeq方法: +数组、列表和元组能使用模式匹配,都是依靠提取器(extractor)机制,它们伴生对象中定义了`unapply`或`unapplySeq`方法: -+ unapply方法用于提取固定数量的对象; -+ unapplySeq用于提取一个序列; ++ **unapply**:用于提取固定数量的对象; ++ **unapplySeq**:用于提取一个序列; -以下是`Array.scala`类源码中定义的`unapplySeq`方法: +这里以数组为例,`Array.scala`定义了`unapplySeq`方法: ```scala 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`; - 自动地生成`equals, hashCode, toString, copy`等方法; -- 伴生对象中自动生成`apply`方法,使得不用new关键字就能构造出相应的对象; +- 伴生对象中自动生成`apply`方法,使得可以不用new关键字就能构造出相应的对象; - 伴生对象中自动生成`unapply`方法,以支持模式匹配。 除了上面的特征外,样例类和其他类相同,可以任意添加方法和字段,扩展它们。 diff --git a/notes/Scala类和对象.md b/notes/Scala类和对象.md index df80bd5..d1e3a0d 100644 --- a/notes/Scala类和对象.md +++ b/notes/Scala类和对象.md @@ -17,7 +17,7 @@ ## 一、初识类和对象 -Scala中的类与Java中的类具有非常多的相似性,这里为了有个直观上的印象,首先给出一个类的示例。 +Scala的类与Java的类具有非常多的相似性,示例如下: ```scala // 1. 在scala中,类不需要用public声明,所有的类都具有公共的可见性 @@ -26,11 +26,11 @@ class Person { // 2. 声明私有变量,用var修饰的变量默认拥有getter/setter属性 private var age = 0 - // 3.如果声明的变量不需要进行初始赋值,此时scala无法进行类型推荐,需要显式指明类型 + // 3.如果声明的变量不需要进行初始赋值,此时Scala就无法进行类型推断,所以需要显式指明类型 private var name: String = _ - // 4. 定义方法,应该指明传参类型和返回值的类型 + // 4. 定义方法,应指明传参类型。返回值类型不是必须的,Scala可以自动推断出来,但是为了方便调用者,建议指明 def growUp(step: Int): Unit = { age += step } @@ -58,7 +58,7 @@ class Person { object Person { def main(args: Array[String]): Unit = { - // 8.创建类的实例对象 + // 8.创建类的实例 val counter = new Person() // 9.用var修饰的变量默认拥有getter/setter属性,可以直接对其进行赋值 counter.age = 12 @@ -120,8 +120,8 @@ object Person { > > ```scala > class Person { -> var name = "" -> private var age = "" +> var name = "" +> private var age = "" > } > ``` > @@ -132,21 +132,21 @@ object Person { > > javap -private Person > ``` > -> 编译结果如下,从编译结果可以看到实际的get和set的方法名,同时也验证了成员变量默认的可见性为public。 +> 编译结果如下,从编译结果可以看到实际的get和set的方法名(因为JVM不允许在方法名中出现=,所以它被翻译成$eq),同时也验证了成员变量默认的可见性为public。 > > ```java > Compiled from "Person.scala" > public class Person { -> private java.lang.String name; -> private java.lang.String age; -> -> public java.lang.String name(); -> public void name_$eq(java.lang.String); -> -> private java.lang.String age(); -> private void age_$eq(java.lang.String); -> -> public Person(); +> private java.lang.String name; +> private java.lang.String age; +> +> public java.lang.String name(); +> public void name_$eq(java.lang.String); +> +> private java.lang.String age(); +> private void age_$eq(java.lang.String); +> +> public Person(); > } > ``` @@ -172,7 +172,7 @@ object Person { ### 2.4 主构造器 -和Java不同的是,Scala类的主构造器直接写在类名后面,同时需要注意以下两点: +和Java不同的是,Scala类的主构造器直接写在类名后面,但注意以下两点: + 主构造器传入的参数默认就是val类型的,即不可变,你没有办法在内部改变传参; + 写在主构造器中的代码块会在类初始化的时候被执行,功能类似于Java的静态代码块`static{}` @@ -206,7 +206,7 @@ heibaiying:20 辅助构造器有两点硬性要求: -+ 辅助构造器的名称必须为this; ++ 辅助构造器的名称必须为this; + 每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。 ```scala @@ -236,7 +236,7 @@ object Person { ### 2.6 方法传参不可变 -在Scala中,方法传参默认是val类型,即不可变,这意味着你在方法体内部不能改变传入的参数。这和scala的设计理念有关,Scala遵循函数式编程理念,强调方法不应该有副作用。 +在Scala中,方法传参默认是val类型,即不可变,这意味着你在方法体内部不能改变传入的参数。这和Scala的设计理念有关,Scala遵循函数式编程理念,强调方法不应该有副作用。 ```scala class Person() { @@ -378,16 +378,19 @@ object Color extends Enumeration { 使用枚举类: ```scala +// 1.使用类型别名导入枚举类 +import com.heibaiying.Color.Color + object ScalaApp extends App { - // 1.使用枚举类型,这种情况下需要导入枚举类,在枚举类中定义的类型别名就有用了 + // 2.使用枚举类型,这种情况下需要导入枚举类 def printColor(color: Color): Unit = { println(color.toString) } - // 2.判断传入值和枚举值是否相等 + // 3.判断传入值和枚举值是否相等 println(Color.YELLOW.toString == "yellow") - // 3.遍历枚举类和值 + // 4.遍历枚举类和值 for (c <- Color.values) println(c.id + ":" + c.toString) } diff --git a/notes/Scala类型参数.md b/notes/Scala类型参数.md index 9e6bae4..59f05a4 100644 --- a/notes/Scala类型参数.md +++ b/notes/Scala类型参数.md @@ -60,9 +60,7 @@ object Utils { ### 2.1 类型上界限定 -Scala和Java一样,对于对象之间进行大小比较,要求被比较的对象实现`java.lang.Comparable`接口。 - -所以如果想对泛型进行比较,需要限定类型上界为`java.lang.Comparable`,语法为` S <: T`,代表类型S是类型T的子类或其本身。示例如下: +Scala和Java一样,对于对象之间进行大小比较,要求被比较的对象实现`java.lang.Comparable`接口。所以如果想对泛型进行比较,需要限定类型上界为`java.lang.Comparable`,语法为` S <: T`,代表类型S是类型T的子类或其本身。示例如下: ```scala // 使用 <: 符号,限定T必须是Comparable[T]的子类型 @@ -126,7 +124,7 @@ trait Ordered[A] extends Any with java.lang.Comparable[A] {