zoukankan      html  css  js  c++  java
  • 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!") }
    }
    

    参考资料

  • 相关阅读:
    JavaScript + Table 系列:排序
    asp.net 2.0中傻瓜式使用soap header
    Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
    asp.net 2.0 导出DataTable到Excel中
    ASP.NET实用技巧(一)
    【ASP.NET】基础补习之FileUpload
    ASP.NET AJAX入门系列(8):自定义异常处理
    Linq To Sql进阶系列(五)Store Procedure篇
    Linq To Sql进阶系列(六)用object的动态查询与保存log篇
    深究“通过样式表实现固定表头和列”
  • 原文地址:https://www.cnblogs.com/rollenholt/p/4109644.html
Copyright © 2011-2022 走看看