Scala Trait

简介:

Scala Trait

大多数的时候,Scala中的trait有点类似于Java中的interface。正如同java中的class可以implement多个interface,scala中的calss也可以extend多个trait。因此你看你会看到类似于这样的代码:

 class Woodpecker extends Bird with TreeScaling with Pecking

scala的trait具有比java中的interface强大的多的功能,正如同java中的abstract class可以具有一些方法实现一样,scala中的trait也可以拥有implemented methods。但是和java中的abstract class不相同的是,你可以将多个trait糅合到一个class中,也可以控制哪些class可以将trait糅合进去。

trait BaseSoundPlayer {
    def play
    def close
    def pause
    def stop
    def resume
}

如果方法不需要任何的参数的话,那么就可以使用def只declare方法的名字,而不需要()。当然如果方法需要参数的话,那么和平时一样,加上括号:

trait Dog {
    def speak(whatToSay: String)
    def wagTail(enabled: Boolean)
}

当一个类继承一个trait的时候,使用的是extend关键字,如果需要集成多个trait的时候,那么需要使用extendwith关键字,也就是第一个trait使用extend,后续的都是用with。如下面的例子:

class Mp3SoundPlayer extends BaseSoundPlayer {...}

class Foo extends BaseClass with Trait1 with Trait2 { ...}

但是如果一个class已经extend另外一个class了,那么如果还想继承其他的trait的话,都必须使用with:

abstract class Animal {

}

trait WaggingTail {
    def startTail { println("tail started") }
    def stopTail { println("tail stopped") }
}

trait FourLeggedAnimal {
    def walk
    def run
}

class Dog extends Animal with WaggingTail with FourLeggedAnimal {
    // implementation code here ...
    def speak { println("Dog says 'woof'") }
    def walk { println("Dog is walking") }
    def run { println("Dog is running") }
}

如果一个class extends一个trait,如果它并没有全部实现trait中定义的抽象方法,那么这个class就必须标记为abstract。

class Mp3SoundPlayer extends BaseSoundPlayer {
    def play { // code here ... }
    def close { // code here ... }
    def pause { // code here ... }
    def stop { // code here ... }
    def resume { // code here ... }
}

// must be declared abstract because it does not implement
// all of the BaseSoundPlayer methods
abstract class SimpleSoundPlayer extends BaseSoundPlayer {
    def play { ... }
    def close { ... }
}

另外,trait也可以extend其他的trait

trait Mp3BaseSoundFilePlayer extends BaseSoundPlayer{
    def getBasicPlayer: BasicPlayer
    def getBasicController: BasicController
    def setGain(volume: Double)
}

定义一个trait,然后给他定义一个faild并且给初始化值,就意味着让它concrete,如果不给值的话,就会让他abstract。

trait PizzaTrait {
    var numToppings: Int // abstract
    var size = 14 // concrete
    val maxNumToppings = 10 // concrete
}

然后对于extends这个PizzaTrait的类中,如果没有给abstract field给值的话,那么就必须标记这个类为abstract、

class Pizza extends PizzaTrait {
    var numToppings = 0 // 'override' not needed
    size = 16 // 'var' and 'override' not needed
}

从上面的例子可以看出,在trait中可以使用var或者val来定义faild,然后在subclass或者trait中不必使用override关键字来重写var faild。但是对于val faild需要使用override关键字。

trait PizzaTrait {
    val maxNumToppings: Int
}

class Pizza extends PizzaTrait {
    override val maxNumToppings = 10 // 'override' is required
}

尽管scala中也有abstract class,但是使用trait更加的灵活.

如果我们想限制那些class可以嵌入trait的话,我们可以使用下面的语法:

 trait [TraitName] extends [SuperThing]

这样只有extend了SuperThing类型的trait, class, abstract class才能够嵌入TraitName, 比如:

class StarfleetComponent
trait StarfleetWarpCore extends StarfleetComponent
class Starship extends StarfleetComponent with StarfleetWarpCore

另外一个例子:

abstract class Employee
class CorporateEmployee extends Employee
class StoreEmployee extends Employee

trait DeliversFood extends StoreEmployee
// this is allowed
class DeliveryPerson extends StoreEmployee with DeliversFood
// won't compile
class Receptionist extends CorporateEmployee with DeliversFood

如果我们想使得Trait只能够被继承了特定类型的类型使用的时候,就可以使用下面的样例:

For instance, to make sure a StarfleetWarpCore can only be used in a Starship , mark the StarfleetWarpCore trait like this:

trait StarfleetWarpCore {
    this: Starship =>
    // more code here ...
}

class Starship
class Enterprise extends Starship with StarfleetWarpCore


trait WarpCore {
    this: Starship with WarpCoreEjector with FireExtinguisher =>
}

表名WarpCore 只能被同时继承了Starship 、WarpCoreEjector 、WarpCoreEjector 这三个东西的东西嵌入

class Starship
trait WarpCoreEjector
trait FireExtinguisher
// this works
class Enterprise extends Starship
with WarpCore
with WarpCoreEjector
with FireExtinguisher

如果我们想限制Trait只能被拥有特定方法的类型所嵌入的话,可以参考下面的例子:

trait WarpCore {
    this: { def ejectWarpCore(password: String): Boolean } =>
}

只有定义有ejectWarpCore方法的classes才能嵌入WarpCore

class Starship {
    // code here ...
}

class Enterprise extends Starship with WarpCore {
    def ejectWarpCore(password: String): Boolean = {
        if (password == "password") {
            println("ejecting core")
                true
            } else {
                false
        }
    }
}

当然也可以要求必须有多个方法:

trait WarpCore {
    this: {
    def ejectWarpCore(password: String): Boolean
    def startWarpCore: Unit
    } =>
}

class Starship
class Enterprise extends Starship with WarpCore {
    def ejectWarpCore(password: String): Boolean = {
        if (password == "password") { println("core ejected"); true } else false
    }
    def startWarpCore { println("core started") }
}

我们可以在object instance创建的时候嵌入Traits。

class DavidBanner
    trait Angry {
    println("You won't like me ...")
}

object Test extends App {
    val hulk = new DavidBanner with Angry
}

这个代码将会输出:“You won’t like me ...”

这个技巧对于debug一些东西的时候比较方便:

trait Debugger {
    def log(message: String) {
    // do something with message
    }
}
// no debugger
val child = new Child
// debugger added as the object is created
val problemChild = new ProblemChild with Debugger

如果你想在Scala中implement Java interface,看下面的例子;

假定现在有3个java interface:

// java
public interface Animal {
public void speak();
}
public interface Wagging {
public void wag();
}
public interface Running {
public void run();
}

我们在Scala中就可以使用类似于下面的写法

// scala
class Dog extends Animal with Wagging with Running {
def speak { println("Woof") }
def wag { println("Tail is wagging!") }
def run { println("I'm running!") }
}

参考资料


==============================================================================
本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/p/4109644.html,如需转载请自行联系原作者

相关文章
|
6月前
|
分布式计算 Java Scala
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
92 0
|
大数据 Scala 容器
【建议收藏】|3分钟让你学会Scala Trait 使用
Scala 是一种强大的静态类型编程语言,其中的 Trait 是一种重要的特性。Trait 可以被看作是一种包含方法和字段定义的模板,可以被其他类或 Trait 继承或混入。在本文中,我们将介绍 Scala Trait 的边界(Boundary)的概念,并展示如何使用它来限制 Trait 的使用范围。
257 11
|
Java Scala
scala面向对象编程之trait特质
特质就像是java的implement,是scala中代码复用的基础单元,它可以将方法和字段定义封装起来,然后添加到类中与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。特质的定义和抽象类的定义很像,但它是使用trait关键字
117 0
scala面向对象编程之trait特质
|
大数据 编译器 Scala
大数据开发基础的编程语言的Scala的Trait
Scala是一种支持面向对象编程和函数式编程的编程语言,它提供了强大的Trait功能。本文将介绍Scala中Trait的概念和用法,帮助开发者更好地理解和应用这门语言。
96 0
|
设计模式 XML Java
基于Scala Trait的设计模式
基于Scala Trait的设计模式
|
Scala
Scala入门到精通——第十一节 Trait进阶
本节主要内容 trait构造顺序 trait与类的比较 提前定义与懒加载 trait扩展类 self type 1 trait构造顺序 在前一讲当中我们提到,对于不存在具体实现及字段的trait,它最终生成的字节码文件反编译后是等同于java中的接口,而对于存在具体实现及字段的trait,其字节码文件反编译后得到的java中的抽象类,它有着scala语言自己的实现方式
3554 0
|
Scala 网络架构 存储
|
Scala 索引 开发工具
|
Java Scala
scala 学习笔记(05) OOP(中)灵活的trait
trait -- 不仅仅只是接口! 接上回继续,scala是一个非常有想法的语言,从接口的设计上就可以发现它的与众不同。scala中与java的接口最接近的概念是trait,见下面的代码: package yjmyzz object App { def main(args...
946 0
|
Java 分布式计算 Spark
SCALA当的trait
不是特别懂,但感觉和RUBY当中的MIX-IN功能有几分相似,这又扯到了多重继承及JAVA当中的接口虚拟类了。。 package com.hengheng.scala class UseTrait { } trait Logger { def log(msg : Strin...
815 0