trait用法汇总

来源:互联网 发布:linux ld错误返回1 编辑:程序博客网 时间:2024/06/16 15:53

trait的功能类似于Java中的interface,但是trait也兼具abstract class的特征,它提供的功能要远比interface和abstract class多很多,以下主要是通过对比trait和interface, abstract class的用法来了解trait的功能。

  • trait和interface的区别
  • trait和abstract class的区别
  • 如何限制哪些class可以继承trait
  • 如何让一个instance object mixin一个trait
  • trait在什么情况下使用extends和with关键词

trait和interface的区别

trait的第一个功能是定义一些抽象方法,使得继承它的类实现这些方法,这和Java的interface相同。但是,interface只能定义方法的prototype, 不能实现这些方法,而trait可以实现它所定义的方法,甚至是所有方法。从这个意义上来说,trait又有点儿像一个普通的class,但是比class更灵活,一个子类只能extends一个父类,但是一个子类可以with多个trait。如果每个trait的方法都有实现,这就实现了Java中不能同时extends多个class的问题。

trait可以extends或with其他traits。

一旦继承了traits,要么声明为abstract class, 要么实现trait的所有方法和域。

trait Animal {    def eat(food: String)     // 抽象方法,带一个参数    def run(legs: Int): Unit  // 抽象方法, 带一个参数和一个返回值,Unit可省略    def sleep = {   //concrete method with no arguemtns        println("Hello, I'm sleeping. Do not interrupt me!")     }}

trait和abstract class的区别

二者共性在于都可以定义方法,即实现方法,也可以定义变量。不同的是,scala对var和val类型的变量处理方式不同, 是否有赋值也有所区别。
val类型的变量必须在声明时赋值,子类需要override父类的这个变量值时,必须显式的声明位override。var类型的变量如果在声明时没有被赋值,就被认为是abstract类型,那么子类继承该trait后,就必须赋值;如果var类型的变量在声明时有初始值,那么子类可以不重新赋值,也可以赋为其他值,此时不需要override,因为它是variable的。
例如:

trait Animal {    val legs = 4            // concrete    var liveArea: String      // abstract    var species = "Crawler"    // concrete    def run(legs: Int): Unit    ...}class Bird extends Animal {    override val legs = 2    var liveArea = "everywhere"     // 注意,var关键字不能少!    def run(legs: Int): Unit = {        println(s"I can run with $legs legs, and I can also fly")    }    ...}

如何限制哪些class可以继承trait

trait有三种方式限制哪些class可以继承它,这是Java无法提供的功能。
- 通过显式定义子类必须要继承哪些类才可以继承该trait,prototype如下:

trait MyTrait {    this: BaseType =>    ....}

任何要继承MyTrait的类,必须是BaseType的子类。
例如:

    trait Animal {        def eat    }    trait Fish {        this: Animal =>    }    class GoldenFish extends Animal with Fish {        def eat = { ... }    }

如果GoldenFish直接继承Fish, 会提示如下错误信息:
test.scala:24: error: illegal inheritance;
self-type GoldenFish does not conform to Fish’s selftype Fish with Animal
class GoldenFish extends Fish {
^
one error found

1.通过定义子类必须要实现的方法类限制可以继承的子类

prototype如下:

MyTrait Fish {    this: {def swim } =>    def eat}

任何要继承Fish的类,必须实现swim方法。例如:

class GoldFish extends MyTrait {    def swim = { println("I'm swimming") }    def eat = { println("what can i eat?") }}

如何让一个instance object mixin一个trait

这个trait的一个特点,可以在创建类实例时将trait mixin。例如我们有如下的trait:

trait Logging {    println("start logging")    def log(msg: String)}class EmptyClass {    def log(msg: String) = {}}val ec = new EmptyClass() with Logging

当执行这行代码后,会打印 “start logging”信息,原因是在创建EmptyClass实例时,Logging自动被继承,构造函数被自动调用。
这对我们添加log信息很有帮助。

trait在什么情况下使用extends和with关键词

规则如下:
如果class只继承一个trait, 那么直接用extends;
如果class继承一个class和一个或多个trait, 那么class用extends, trait用with;
如果class继承多个trait, 第一个trait用extends,其他的用with;
也就是有class优先将extends给该class, with给trait。

0 0
原创粉丝点击