Scala(2)

Funtional Objects

  • 这一章继续介绍有关class的内容。不过,这一章跟前面那章介绍class的不同,这一章主要是介绍object,就是没有mutable state的class,这样才符合函数式编程的要求。

  • 首先,介绍class的class parameter。class parameter就是传递给class的参数,同传递给函数的参数一样,在这里也不能省略参数的类型,因为Scala不能推导出来

  • 另外,和前面介绍那样,在Scala不需要自己构造不必要的constructor,Scala会构造constructor,叫做primary constructor,把传递进来的class parameter赋给同样名字的参数。这样,我们可以用直接在class内部,使用同样名字的参数了

  • 注意,传递进来的class parameter只可以在class内部,如果要在class外部访问这个参数,需要定义一个field,然后把参数赋值给这个field,然后访问field

  • 在Class中,如果不是field或者method定义,那么这些语句也会成为primary constructor的一部分,在实例化一个对象时也会被调用

  • 除了Scala自己定义的constructor,也可以自己定义constructor。自己定义的constructor,叫做auxiliary constructor,方法名叫做this。在auxiliary constructor,可以调用primary constructor,还可以调用自己定义的其他的auxiliary constructor。但是注意,不管怎么调用,最后都是调用primary constructor。也就是说,pirmary constructor是class的唯一入口

  • Scala,标识符的名字规则也和Java类似,建议采用驼峰法。另外,标识符有很多种,包括+,-等符号等可以算作标识符。这样,我们就可以直接定义一个 + 这样的方法,作为我们class的+运算。(因为这符合Scala的pure object-oriented原则,所有运算都是method call,自然要把+这样原来的运算符作为标识符来对待)

  • Class内部,默认可见性都是public,不需要显示声明。如果需要private,或者protected才需要显示声明

  • 其他的和普通object-oritented语言类似,也包括了this指针,method overloading等

  • Scala还提供了implicit conversion,可以把内置类型转化成我们自己定义的class类型,只需要定义相应的转换方法就好了,然后Scala编译器就会在内部做隐式转换,不需要自己在显示转换了。要定义implicit conversion method,需要关键字implicit,而且这个conversion method不能定义在class内部,而是需要be in scope

  • 一个推荐的方法是把implicit coversion method放在对应的companion object

Built-in Control Structures

  • 这一章主要介绍Scala内置的Control Structure。在Scala,基本的控制结构包括了if、while、do-while、for、try、catch。除了while、do-while是语句外,其他的都是表达式,但会返回一个值的,这也是函数式语言与命令式语言的不同。

  • 比较有趣的是for循环,除了可以进行迭代之外,也同样支持yield关键字,用来生成一个新的collection

  • yield可以用来生成一个generator,还可以嵌套yield(这里的嵌套yield是我的理解,其实根据yield的特性,如果在表达式使用了yield,那么下次使用这个表达式时,它就会返回一个值。这样,即使在外层再次yield时,内层的yield已经返回一个值了)。比如,来生成一个乘法表,生成结果如图:

demo

源代码:


  def makeExpr(x: Int, y: Int): String = {

    val res = (x * y).toString

    val sp = " " * (4 - res.length)

    x.toString + " * " + y.toString + " = " + res + sp

  }



  def multiTable() = {

    val table =

      for (x <- 1 until 4) yield {

        for (y <- 1 until 4) yield {

          makeExpr(x, y)

        }

      }

    table.mkString("\n")

  }

不过,这样格式不是很好看。可以在内层yield中,使用变量来接受yield返回的值,在对值做一些个格式上的处理,然后外层yield返回的就是这个处理过格式的值了

  • 不过,在Scala中,没有了breakcontinue,这是因为它们会和functional literal冲突。所以,就把它们删去了。

  • Scala有个强大的pattern matching,与C++不一样,pattern可以是任意的常量表达式,而不只是数字或者枚举类型了。另外,在match语句中,如果匹配了一个结果,是不会进行fall out(毕竟没有了关键字break,不过这样也挺好的,省的我忘记匹配一个模式后又忘记写break了)

  • 匹配有个通配符 _,可以用来匹配任意的pattern

  • Variable scope规则倒是和C++、Java类似。都是内层的变量覆盖外层的变量。

  • 异常处理语句格式和Java的类似。不过,要注意,throw是一个表达式,会返回一个result type,一般地,这个result type就是Nothing。同样的,try-catch-finally也会results in a value。result in a value的意思是 1.当没有exception is thrown,那么就返回try语句的结果。 2. 如果有异常出现,而且被捕捉到了,那么就返回catch语句的结果。 3. 如果有异常出现,但是没有被捕捉到,那么这个表达式has no result at all(no result意味着Nothing,因为exception的类型就是Nothing,因为没有捕获到异常,那么这个异常就会往上报,所以返回类型就是Nothing,自然has no result at all)。同时,还要注意的是 The value computed in the finally clause is dropped。这跟Java不同,在Java中如果你在finally语句中计算了一个值,那么最后结果是这个值才对。但是在Scala中,finally一般不用来计算值(因为会被dropped),而只是用来做一些clean up job

  • 上面说的finally语句中计算的值会被drop,这不是绝对的。事实上,值会被drop是因为这是一个expression,如果你显示的加上一个return语句,那么最终 return value will “overrule” any previous one that originated in the try block or one of its catch clauses,这也适用于exception语句。举例来讲,定义如下两个函数:


def  f() : Int  = try {return 1} finally {return 2}

def  g() : Int  = try {1} finally {2}

如果调用 f(),结果是2(因为显示使用了return,overrule previosu result 1);而调用 g(),则结果是1 , 2则被drop

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值