scala 笔记

 

1. scala 的函数的参数默认都是val类型的

2. _ 参数占位符

3. 偏应用函数,类似于python 函数赋值到另外一个变量:

def sum(a,b,c):
    return a+b+c
sum(1,2,3) // 输出6
a = sum
a(1,2,3) // 输出6

  在scala中:

def sum(a:Int, b:Int, c:Int) = a + b + c

sum(1,2,3) // 输出6
val a = sum _
a(1,2,3) //输出6
val c = a
c(1,2,3) //输出6

  还可以这样用 val b = sum(1, _: Int, 3); b(2) // 输出6

4. 闭包

短文本函数(x:Int)=> x>0, 现在考虑这种情况的短文本函数: (x:Int)=> x>more

more是什么呢? more应该是一个变量,但是没有在该函数文本中定义。x 是一个绑定变量,因为其在函数文本中有定义

与python中类似,闭包返回的是一个函数值,这个函数值的文本中访问了该闭包的局部变量,如

def makeIncreaser(more: Int) = (x: Int) => x + more

闭包makeIncreaser 返回函数值 (x: Int) => x + more, 该函数值访问了闭包的变量more

scala> val inc1 = makeIncreaser(1)

inc1: (Int) => Int = <function>

scala> val inc9999 = makeIncreaser(9999)

inc9999: (Int) => Int = <function>

创建了两个函数。 尽管more 是一个已经返回的函数调用的参数,scala编译器会在堆中重新安排1 和 9999的存在以让返回的函数值去捕获。 除了参数还可以是任意val,var。

 5. 变长参数

   def func(fmt:String, args:Type*) ....

    用 args:Type*表示变长部分,在函数内部,args 会被当做 Array[Type]

 调用时候 : func("format", a , b)

 或者 :  func("format", array: _*)  用  _* 表示把array展开。

 类似于python中: def func(fmt, *args): pass

   func(fmt, *argList)   // py中吧*args 当做tuple

 

6. 尾递归

 在递归函数最后一个动作调用自己的函数,被称为尾递归:tail recursive。Scala编译器检测到尾递归就用新值更新函数参数,然后把它替换成一个回到函数开头的跳转。 注意最后一个动作是调用自身,甚至连自身的偏应用函数都不行。

7. curry 化

 感觉curry化与偏应用函数指定部分参数差不多

 def curriedSum(x: Int)(y: Int) = x + y

 curriedSum(1)(2)

这里发生的事情是当你调用curriedSum,你实际上背靠背地调用了两个传统函数。第一个函数调用带单个的名为x的Int参数,并返回第二个函数的函数值。第二个函数带Int参数y.

val onePlus = curriedSum(1)_

onePlus(2) // 3

 

8.  如果函数只有一个参数,那么调用时候可以用{}代替(), scala里这个机制主要是考虑到函数作为参数的时候,如果直接写函数文本采用{}可以让程序员写包围在{}的函数文本。

println("hello world") 可以写成println{"hello world"}

对于两个参数或者更多参数的函数不能用{}代替(),但可以结合偏应用函数来使用或者把两参函数定义成curry函数:

        def func(a:Int, b:Int) = a + b       
        val funp = func(_:Int, 3)
        println{funp{2}}
        
        def funcurry(a:Int)(b:Int) = a + b
        println{funcurry(3){5}}

  不过上面例子中的参数不是函数,在非函数情况下没必要用{}

 

9.  叫名参数

def myAssert(predicate: ()=>Boolean) {

  if(!predicate){

           throw new AssertionError

      }

}

调用: myAssert{() => 5 > 3}

叫名参数,要定义参数的类型开始于=>而不 是() =>, 叫名类型中,空的参数列表,(),被省略,它仅在参数中被允许

def myAssert(predicate: =>Boolean) { .... }

调用: myAssert(5>3)

 

10. Scala 里禁止在同一个类里定义同名的字段和方法

11. Null 是所有类的子类,Null是null类型的引用;Nothing是任何类型的子类

12. Scala 类型也是单一继承的

13. trait  类似于java中的interface,不过允许实现方法,也是类型也占内存的

     我觉得引入特征,其实为了有很像c++中的多继承。 trait 与类没多大区别,除了不能有类参数;类中的super是静态绑定的,特征中的super是动态绑定的,需要看混入到具体哪个类才能确定super指谁;特征具有堆叠性质,这点多继承没有(多继承的supper调用也必须明确哪个上层类的方法,属于静态绑定)。 混入多个特征,越后的越先被应用

14. Ordered trait, 混入这个ordered 特征,你只需要实现compare 方法,就能自动的定义了 <,  >,  <=,  >= 4个方法

15. 特征线性化顺序:

 

16. 断言

Scala 在方法里除了可用 assert() 方法像 Java 那样进行断言,还可以使用 ensuring() 方法在返回结果的分支的花括号同一行上进行断言。它们不同的是 assert 可以随意放在哪里对任何的 boolean 类型进行断言,而 ensuring 是用来对返回结果行断言的,所以它必须尾随返回结果处。 assert 和  ensuring 方法都是定方在 Predef 中的,所以可以直接写。 断言可以使用jvm里的-ea和-da命令行标志开放和禁止。

01
02
03
04
05
06
07
08
09
10
private def widen(w: Int): Element = {
    if(w < width){
        this
    } ensuring(_.width > 10) //这里欲断言返回结果 this,所有两 if 后的花括号不能省略
    else {
        val left = elem(' ', (w - width)/2, height)
        var right = elem(' ', (w - width - left.width, height)
        left beside this beside right
    } ensuring(w <= _.width) //断言的是上一行 left beside this beside right 结果
} ensuring((w + _.width) > 100//ensuring 断言可以放在方法体外了,用来断言最终的结果

17.  case 类

    a. 自动生成与类同名的工厂方法,于是A(x) 等同于 new A(a)

    b. 自动为构造参数隐式的加上了val (scala 类的构造参数前加var/val ,自动生成相应的成员以及存取方法)

    c. 自动实现toString, hashCode, equals方法

    d. 支持模式匹配

18. 模式匹配

     匹配:

  1. arg match {
  2. case "salt" => println("pepper")
  3. case "chips" => println("salsa")
  4. case "eggs" => println("bacon")
  5. case _ => println("huh?")
  6. }  //match表达式有值

    通配模式:_     常量模式:5,“hello”, Nil 只匹配空列表     变量模式: E match { case pi => 3.14159265} ,变量模式可以匹配任何输入,因此之后的情况不会被访问到的,可以用常量代替(小写字母开头的pi (val pi)会被当做变量,但`pi`则被当做常量)

    构造器模式   序列模式  元组模式(元组模式不同于序列模式的地方是,其不能指定_*,必须是固定元素个数匹配)

    类型模式(类型擦除,数组除外)

    

19. 模式守卫: 就是在模式匹配时候 加 if 表达式,为真才匹配成功

20. 封闭类: sealed class, 除了在类定义所在的文件外,不能再其它地方添加任何新的子类。这个规则将有利于编译器为你的模式匹配检测出未匹配的模式(当然你也可以用(e: @unchecked) match {}方式禁掉编译器穷举所有模式检查)

21. Option类型,如Option[String]类型的变量是可选的String,可以用模式匹配分离其值Some或者None

   def show(x: Option[String]) = x match {

        case Some(s) => s

        case None => "?"

   }

 

22.  模式匹配的主要应用: 变量定义,偏函数样本,for表达式

 23. Option,以下来自effective scala

Option 

Option是一个包含或者不包含某些事物的容器。

Option的基本接口类似于:

1
2
3
4
5
trait Option[T] {
  def isDefined: Boolean
  def get: T
  def getOrElse(t: T): T
}

Option本身是泛型的,它有两个子类:Some[T]None

我们来看一个Option的示例: Map.get使用Option来作为它的返回类型。Option的作用是告诉你这个方法可能不会返回你请求的值。

1
2
3
4
5
6
7
8
scala> val numbers = Map(1 -> "one", 2 -> "two")
numbers: scala.collection.immutable.Map[Int,String] = Map((1,one), (2,two))
 
scala> numbers.get(2)
res0: Option[java.lang.String] = Some(two)
 
scala> numbers.get(3)
res1: Option[java.lang.String] = None

现在,我们要的数据存在于这个Option里。那么我们该怎么处理它呢?

一个比较直观的方法就是根据isDefined方法的返回结果作出不同的处理。

1
2
3
4
5
6
7
//如果这个值存在的话,那么我们把它乘以2,否则返回0。
 
val result = if (res1.isDefined) {
  res1.get * 2
} else {
  0
}

 

不过,我们更加建议你使用getOrElse或者模式匹配来处理这个结构。

getOrElse让你可以很方便地定义一个默认值。

1
val result = res1.getOrElse(0) * 2

模式匹配可以很好地和Option进行配合使用。

val result = res1 match { case Some(n) => n * 2 case None => 0 }

 

25. covariant 要求类的成员是非可变的(不会改变成员内容),同时不能有这样的成员函数:以参数类型为参数类型

26. 协变与逆变http://www.tuicool.com/articles/vaAnmq

 

posted on 2015-05-01 16:29  不忘初衷,方能致远  阅读(413)  评论(0)    收藏  举报

导航