Scala Trait

1. Trait

  • trait 是一种支持多重继承的类。类、case类、对象,以及trait都只能扩展不超过一个类,但是可以同时扩展多个trait。不过,与其他类型不同,trait不能实例化。

  • 语法:定义trait

    trait <identifier> [extends <identifier>] [{ fields, methods, and classes }]
  • trait看起来与其他类型的类是一样的。不过,类似对象,trait不能有类参数。但与对象不同的是,trait可以有类型参数。

  • trait在父类的后面
    如果扩展了一个类以及一个或多个trait, 需要先扩展这个类,然后在使用with关键字增加trait。如果指定了父类,父类必须放在所有父trait前面。

  • Scala如何用trait支持多重继承?
    尽管Scala理论上支持多重继承,但是编译器实际上会创建各个trait的副本,形成类和trait组成的一个”很高”的单列层次体系。所以,如果一个类扩展了类A以及trait B和C,编译到.class二进制文件时,实际上它会创建一个类,这个类又扩展了另一个类,后者进一步扩展了下一个类。
    这里将所扩展的类和trait的水平列表变换为一个垂直的链,各个类分别扩展另一个类,这个过程称为线性化(linearization)。这是一种复制机制,用于在只支持单重继承的执行环境中支持多重继承。

  • 如果trait有竞争成员会发生什么?
    如果一个类导入两个trait,他们有相同的字段或成员,但是没有override关键字,这个类的编译就会失败。这个编译错误就好像你要扩展一个类,并且提供了你自己的方法,但是没有增加override关键字一样。对于trait,可以增加一个公共的基类,然后用override关键字覆盖字段和方法,这样可以确保trait能够由同一个类扩展。

  • 多重继承的顺序为从右向左(从最低的子类到最高基类),如果一个类定义为class D extends A with B with C, 其中A是一个类,B和C是trait, 将由编译器重新实现为class D extends C extends B extends A。最右定义的trait(C)是所定义的类(D)的直接父类,这个类或第一个trait(A)成为最后一个父类。

2. 自类型

  • 自类型(self type)是一个trait注解,向一个类增加这个trait时,要求这个类必须有一个特定的类型或子类型。有自类型注解的trait不能增加到未扩展指定类型的类。

  • 自类型的一种流行用法是用trait为需要输入参数的类增加功能。trait扩展有输入参数的类不容易,因为trait本身不能有输入参数。不过,trait可以用一个自类型注解声明自己是这个父类的一个子类型,然后增加响应的功能。

  • 语法: 定义自类型

    trait ..... { <identifier>: <type> => ... }
  • 要把自类型增加到trait定义中开始大括号的后面,包括一个标识符,请求的类型和一个箭头(=>)。有自类型的trait可以访问该类型的字段,就好像显示扩展了那个类型一样。

  • 自类型使用的标准标识符是”self”, 不过也可以使用任何其他标识符。也就是说,除了类似this的关键字,可以使用任何标识符。使用常用标识符”self”的好处是,这样会使你的代码对其他Scala开发人员更可读。

  • 利用自类型,trait可以扩展一个类而不用指定其输入参数。另外这也是一个为trait增加限制和/或需求的安全方法,可以确保它们只能在特定的上下文中使用。

3. 用Trait实例化

  • 类实例化时增加的trait会扩展这个类,而不是由类扩展trait。Trait线性化的顺序为从左到右,这包括实例化的类,所以所有trait都会扩展这个类,而不是反过来扩展trait。

  • 举例说明:下面的例子,类由一个trait扩展,这个trait有该类的自类型,从而保证这个trait会扩展这个类

    scala> class A
    defined class A
    
    scala> trait B { self: A => }
    defined trait B
    
    scala> val a = new A with B
    a: A with B = $anon$1@5965be2d
    
  • 用trait实例化的真正意义在于可以为现有的类增加新的功能或配置。这个特性通常被称为依赖注入(dependency injection),因为父类所依赖的具体功能是在类定义之后增加的,所以会在类实例化时为类”注入”这个特性。这也说明,这个类的两个实例可以在完全不同的配置下操作,因为实例化时可能增加了不同的可配置trait。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值