抠腚爱揉曼 Coding Iron Man

17Aug/104

Scala笔记2

最近几天杂事很多,导致那本薄薄的Scala至今未看完……今天先来接一下Scala笔记2

  • Scala的访问控制机制和Java有别。有些许的概念不同而且能够做到更加细粒度的控制。Scala默认访问修饰为public,Java则是微妙的default。Scala中的protected则比Java更小气,它只对自己和派生类可见,同包下的其它类无法访问,而且类也只能访问自己的基类中的protected成员,无法访问继承同样基类的其余派生类中的基类protected成员。Scala对细粒度访问控制体现在private和protected修饰可以通过方括号指定额外的报名或类名来赋权。
  • Scala中调用方法传递参数时,可以选择使用圆括号和花括号,它们是等价的。花括号这个语法糖结合curry可以使抠腚鹅们写出看上去更爽的代码,比如自制while循环原语,见下面的代码清单。
    object MakeYourWhile {
        def main(args: Array[String]) {
            var i = 0
            myWhile(i < 4) { //第一个参数使用圆括号,第二个使用花括号
                i += 1
                println(i) // 输出了1 2 3 4
            }
        }
    
        // 定义一个myWhile方法对象,参数是一个返回Boolean的方法和一个返回Unit的方法
        def myWhile(p: => Boolean)(f: => Unit) {
            if (p) {
                f
                myWhile(p)(f)
            }
        }
    }
  • Scala没有static修饰符,它用object为类添加类级别的成员。其实用object声明的类就是一个单例对象,抠腚鹅们可以像使用静态成员一样通过类名调用它们。同名的class和object声明被称为独立对象(class)和伴生对象(object),它们被认为是同一个类,可以互相访问彼此的private成员。
  • Scala拥有严格而灵活的泛型定义(一个让人有点头晕却又强大的特性)。Scala可以显示的定义类型转换是否支持协变和逆变,同时还可以限定类型参数在继承关系中的上下届,下面的代码清单折腾了这些特性。
    object SoManyCar {
        def main(args: Array[String]) {
            val chevrolet0 = new Something0[Chevrolet]
            val car0: Something0[Car] = chevrolet0 // 编译错误 不允许把派生类容器赋给基类
    
            val chevrolet1 = new Something1[Chevrolet]
            val car1: Something1[Car] = chevrolet1 // 不报错 因为+T的类型声明告诉Scala支持协变
    
            val car2 = new Something2[Car]
            val chevrolet2: Something2[Chevrolet] = car2 // 这都行?!-T的类型声明让Scala支持逆变 Java可不带这么玩的
    
            val car3 = new Something3[Car] // 编译错误 T <: Chevrolet声明了类型下界为Chevrolet 所以不允许Chevrolet的基类Car
            val chevrolet3 = new Something3[Chevrolet]
            val cruze3 = new Something3[Cruze]
    
            val car4 = new Something4[Car]
            val chevrolet4 = new Something4[Chevrolet]
            val cruze4 = new Something4[Cruze] // 编译错误 T >: Chevrolet声明了类型上界为Chevrolet 所以不允许Chevrolet的派生类Cruze
        }
    }
    
    class Car {}  // 唔 这是一辆车
    class Chevrolet extends Car {} // 嗯 这是一辆雪佛兰
    class Cruze extends Chevrolet {} // 好了 这是一辆科鲁兹
    
    class Something0[T] {} // 普通
    class Something1[+T] {} // 协变
    class Something2[-T] {} // 逆变
    class Something3[T <: Chevrolet] // 限定下界
    class Something4[T >: Chevrolet] // 限定上届
  • trait,Scala中相当让人头晕却又相当神奇而强大的特性。trait,意指特质,在Scala中它类似带有部分实现的接口(编译的时候其实就是被处理成了一个interface和一个helper类)。对于trait,混入这个概念比继承更清晰。一个类可以被混入叠加多种特质,更进一步,trait甚至还可以只叠加到一个特定对象上,通过在运行时使用with关键字来创建新对象的方法。下面的代码清单尝试演示trait的特性,同时展示了其中特殊的super调用概念。
    object TraitTest {
    def main(args: Array[String]) {
    val people1 = new People with Cruze // 有科鲁兹的路人甲
    val people2 = new People with Cruze with Sagitar // 有科鲁兹又有速腾的路人乙
    // 在people2中Sagitar的super调用了Cruze中的方法 而Cruze中的super调用又跑到了它extends的Car上
    println(people1 haveCar)
    println(people2 haveCar)
    }
    }
    
    class People {
    }
    
    abstract trait Car {
    def haveCar(): List[String] = List[String]() // haveCar返回一个空数组
    }
    trait Cruze extends Car {
    override def haveCar(): List[String] = "CRUZE" :: super.haveCar() // 俺有一辆科鲁兹
    // 其中的super调用实际上是延迟绑定的 在运行时被指向到当前trait链左边的trait
    }
    trait Sagitar extends Car {
    override def haveCar(): List[String] = "SAGITAR" :: super.haveCar() // 俺有一辆速腾
    }
  • Scala可自定义隐式类型转换,通过implicit关键字定义一个转换对象的函数来支持自定义隐式类型转换。这个特性也是被设计用来支持在Scala上构建DSL的。下面从图灵那本Scala的书中抄了一段代码过来演示……
    object ImplicitTest {
        // 一个将Int隐式转换为DateHelper的转型方法
        implicit def int2DateHelper(number: Int) = new DateHelper(number)
        val ago = "ago"
        val from_now = "from_now"
    
        def main(args: Array[String]) {
            println(2 days ago)
            println(5 days from_now)
        }
    }
    
    import java.util.{Date, Calendar} // 哈 可以在代码中间import
    class DateHelper(number: Int) {
        def days(when: String): Date = {
            val date = Calendar.getInstance
            when match {
                case "ago" => date.add(Calendar.DAY_OF_MONTH, -number)
                case "from_now" => date.add(Calendar.DAY_OF_MONTH, number)
                case _ => date
            }
            date.getTime
        }
    }

好了,2就2到这儿了,未完待续……

Posted by Anson

Tagged as: , Leave a comment
Comments (4) Trackbacks (0)
  1. 你这不逼着哥找一张宽一点的皮么~

  2. 这张够宽了……起码哥公司电脑还是1280*1024的分辨率
    另外我就知道你果然会来加read more的tag……

  3. 飞飞威武啊!
    1280×1024是个啥分辨率?


Leave a comment

(required)

No trackbacks yet.