博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scala Trait
阅读量:6933 次
发布时间:2019-06-27

本文共 5568 字,大约阅读时间需要 18 分钟。

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 methodsabstract 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 StarfleetComponenttrait StarfleetWarpCore extends StarfleetComponentclass Starship extends StarfleetComponent with StarfleetWarpCore

另外一个例子:

abstract class Employeeclass CorporateEmployee extends Employeeclass StoreEmployee extends Employeetrait DeliversFood extends StoreEmployee// this is allowedclass DeliveryPerson extends StoreEmployee with DeliversFood// won't compileclass 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 Starshipclass Enterprise extends Starship with StarfleetWarpCoretrait WarpCore {    this: Starship with WarpCoreEjector with FireExtinguisher =>}

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

class Starshiptrait WarpCoreEjectortrait FireExtinguisher// this worksclass Enterprise extends Starshipwith WarpCorewith WarpCoreEjectorwith 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 Starshipclass 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 debuggerval child = new Child// debugger added as the object is createdval problemChild = new ProblemChild with Debugger

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

假定现在有3个java interface:

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

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

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

参考资料

转载地址:http://zigjl.baihongyu.com/

你可能感兴趣的文章
.Net转Java.02.数据类型
查看>>
在一个gradle 的maven property 里添加多个URL
查看>>
PHP中的SESSION
查看>>
C#正则表达式的完全匹配、部分匹配及忽略大小写的问题
查看>>
【游戏开发】基于VS2017的OpenGL开发环境搭建
查看>>
洛谷P3960 列队(动态开节点线段树)
查看>>
RESTful到底是什么玩意??
查看>>
PHP的词法解析器:re2c
查看>>
Html5版本的全套股票行情图开源了,附带实现技术简介
查看>>
Our Proof : Page Scraping : Website Data Extraction : Data Mining Analytics : Connotate.com
查看>>
linux 时间戳及时间差计算
查看>>
[Dynamic Language] Python 静态方法、类方法、属性
查看>>
在 Delphi 下使用 DirectSound (5): 获取或设置缓冲区的格式:
查看>>
select 语句的执行顺序
查看>>
wayos利用easyradius实现WEB认证页面的记住密码及到期提醒功能
查看>>
软件工程 软件的估计为什么这么难
查看>>
struts2标签
查看>>
[Cocoa]深入浅出Cocoa之多线程NSThread
查看>>
Silverlight运行原理经典问答。
查看>>
服务器
查看>>