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
的时候,那么需要使用extend
和with
关键字,也就是第一个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!") }
}
参考资料
Scala Trait的更多相关文章
- scala的trait执行报错: 错误: 找不到或无法加载主类 cn.itcast.scala.`trait`
scala的trait执行报错: 错误: 找不到或无法加载主类 cn.itcast.scala.`trait`.Children 原因:包名写成了trait,与trait关键字重名了: package ...
- Scala trait特质 深入理解
Scala trait特质 深入理解 初探Scala 特质trait 在Scala中,trait(特质)关键字有着举足轻重的作用.就像在Java中一样,我们只能在Scala中通过extends进行单一 ...
- 学习scala trait
// 类接口,但是可以实现方法 // 作用 多重继承 trait traitA{ val tnum: Int def log(msg: String): Unit ={ println(" ...
- Beginning Scala study note(7) Trait
A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...
- Scala入门系列(八):面向对象之trait
基础知识 1 将trait作为接口使用 此时Trait就与Java中的接口非常类似,不过注意,在Scala中无论继承还是trait,统一都是extends关键字. Scala跟Java 8前一样不支持 ...
- 【Scala篇】--Scala中Trait、模式匹配、样例类、Actor模型
一.前述 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 模式匹配机制相当于java中的switch-case. 使用了case关键字的类定义就是样例类(case ...
- 【Scala学习之二】 Scala 集合 Trait Actor
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...
- 8、scala面向对象编程之Trait
一.Trait基础 1.将trait作为接口使用 // Scala中的Triat是一种特殊的概念 // 首先我们可以将Trait作为接口来使用,此时的Triat就与Java中的接口非常类似 // 在t ...
- Beginning Scala study note(9) Scala and Java Interoperability
1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...
随机推荐
- Wabpack系列:在webpack+vue开发环境中使用echarts导致编译文件过大怎么办?
现象,在一个webpack+vue的开发环境中,npm install echarts --save了echarts,然后在vue文件中直接使用 import echarts from 'echart ...
- 用Dart&Henson玩转Activity跳转
用Dart&Henson玩转Activity跳转 Extra是Android标准的组件之间(Activity/Fragment/Service等)传递数据的方式.本文介绍了开源项目Dart的使 ...
- 狗屎的Java规范
规范 标题真有点侮辱了狗. 最近做Java,C#与Java对比笔记: http://www.cnblogs.com/newsea/p/4839540.html 其实Java语法弱点就弱点,关键是Jav ...
- 项目分布式部署那些事(2):基于OCS(Memcached)的Session共享方案
在不久之前发布了一篇"项目分布式部署那些事(1):ONS消息队列.基于Redis的Session共享,开源共享",因为一些问题我们使用了阿里云的OCS,下面就来简单的介绍和分享下相 ...
- [C#解惑] #1 在构造函数内调用虚方法
谜题 在C#中,用virtual关键字修饰的方法(属性.事件)称为虚方法(属性.事件),表示该方法可以由派生类重写(override).虚方法是.NET中的重要概念,可以说在某种程度上,虚方法使得多态 ...
- Trilateration三边测量定位算法
转载自Jiaxing / 2014年2月22日 基本原理 Trilateration(三边测量)是一种常用的定位算法: 已知三点位置 (x1, y1), (x2, y2), (x3, y3) 已知未知 ...
- php file_get_contents失败[function.file-get-contents]: failed to open stream: HTTP request failed!解决
在使用file_get_contents方法来获取远程文件时会出现 [function.file-get-contents]: failed to open stream: HTTP request ...
- python代码缩进
习惯了java,c++之类的宽容,初学python,被它摆了道下马威,写if else,竟然必须要我正确用缩进格式,原来在python里不能用括号来表示语句块,也不能用开始/结束标志符来表示,而是靠缩 ...
- python基础_制作多级菜单_(运用:字典_列表_元组等知识)
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author: nulige db = {} path = {} while True: temp = db ...
- myeclipse下java文件乱码问题解决
中文乱码是因为编码格式不一致导致的.1.进入Eclipse,导入一个项目工程,如果项目文件的编码与你的工具编码不一致,将会造成乱码.2.如果要使插件开发应用能有更好的国际化支持,能够最大程度的支持中文 ...