一文解说 Scala Trait 所有用法



转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com

AIQ 机器学习大数据 知乎专栏 点击关注

Trait 基础

  1. 在 Scala 中,Trait 是一种特殊概念。首先,Trait 可以被作为接口来使用,此时 Trait 与 Java 的接口非常类似。同时在 Trait 可以定义抽象方法,其与抽象类中的抽象方法一样,不给出方法的具体实现。 
    _ 注意:_ 类使用 extends 继承 Trait,与 Java 不同,这里不是 implement,在 Scala 中,无论继承类还是继承 Trait 都是用 extends 关键字。

    在 Scala 中,类继承 Trait 后,必须实现其中的抽象方法,实现时不需要使用 override 关键字,同时 Scala 同 Java 一样,不支持类多继承,但支持多重继承 Trait,使用 with 关键字即可。 
    8a2184b5396547de903d3c1a83b41e56.png

  2. 在 Trait 中定义具体方法:通俗来讲,就是 trait 可以包含一些很多类都通用的功能,如打印日志等,在 Spark 中也使用 Trait 定义了通用的日志打印方法。也就是说 Scala 中的 Trait 不只定义抽象方法,还可以定义具体方法,也有的说法是 Trait 的功能混入了类。 

  3. 在 Trait 中定义具体字段:在 Scala 中,Trait 可以定义具体字段,继承 Trait 的类就自动获取了 Trait 中定义的类。 
    _ 注意:_ 这里与继承 Class 不同,如果继承 Class 获取的字段,实际定义在父类中,而继承 Trait 获取的字段,就直接添加到了类中。 
    3e1b409745cd44c3b3562981cffca675.png

  4. 在 Trait 中可以定义抽象字段,而 Trait 中的具体方法可以基于抽象字段来编写,但继承 Trait 的类,则必须覆盖抽象的 field,提供具体的值。 
    95641604c9a445538b4427174e3dc8d7.png


Trait 进阶

  1. 为实例混入 Trait:在创建某个类的对象时,可以指定该对象混入某个 Trait,这样只有这个对象混入了该 Trait,其他对象则没有 
    2c5a3c4a44364d009270af7178478cee.png

  2. Trait 调用链:在 Scala 中,支持让类继承多个 Trait,依次调用多个 Trait 中的同一个方法,只要让多个 Trait 中的同一个方法中,在最后都执行 super 方法。 
    _ 注意:_ 在类中调用多个 Trait 中都有的方法时,首先会从最右边的 Trait 的方法开始执行,然后依次向左执行,形成一个调用条。这个相当于设计模式中的责任链模式的一种具体实现依赖。 
    7b61d310f0ec4b6b97b360d68c935b70.png

  3. 在 Trait 中覆盖抽象方法:在 Trait 中,可以覆盖父 Trait 的抽象方法,但是覆盖时,如果使用了 super 方法的代码是无法通过编译的。如果要通过编译,就得给子 Trait 的方法加上 abstract override 修饰。

trait Logger {  def log(message: String)
} trait MyLogger extends Logger {  abstract  override  def log(message: String) { super.log(message)
 }
}

Trait 高级

  • 混合使用 Trait 的具体方法和抽象:可以让具体方法依赖于抽象方法,抽象方法放到继承 Trait 的类中实现; 
    ffc4a04fe64841c7a66a499562b85faa.png

  • Trait 构造机制: 在 Scala 中,Trait 是有构造代码的,就是 Trait 中不包含在任何方法中的代码,而继承了 Trait 的构造机制如下: 
    1)父类的构造函数 
    2)Trait 的构造代码执行,多个 Trait 从左向右依次执行 
    3)构造 Trait 时会先构造父 Trait,如果多个 Trait 继承同一个父 Trait,则父 Trait 只会构造一次 
    4)所有 trait 构造结束之后,子类的构造函数执行 

  • Trait 字段的初始化:在 Scala 中,Trait 是没有接收函数的构造函数,这是 Trait 与 Class 的唯一区别,如果要求 trait 对字段进行初始化,智能使用 Scala 中的一种高级特性,即提前定义或使用 Lazy Value。

trait Greet{  val message: String
 println(message.toString)
} class Person  val p = new { val message: String = "Hello" } with Person with Greet //或者是  class Person extends {  val message: String = "Hello" } with Greet { }

另一种方式为使用 lazy value 
3bd5c75e3ede4f068e23badc6c372b11.png

最后,Trait 还继承 class:在 Scala 中,Trait 可以继承 class,这个 class 就会成为所有继承该 trait 的类的父类


更多高质资源 尽在AIQ 机器学习大数据 知乎专栏 点击关注

转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com