您现在的位置是:首页 > 文章详情

Scala Trait

日期:2018-01-06点击:472

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,如需转载请自行联系原作者

原文链接:https://yq.aliyun.com/articles/336556
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章