鍍金池/ 教程/ Scala/ Trait 的基本概念
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達(dá)式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達(dá)式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達(dá)式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實(shí)現(xiàn)方法
try 表達(dá)式處理異常
選擇瘦接口還是胖接口設(shè)計?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進(jìn)一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實(shí)現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調(diào)用基類構(gòu)造函數(shù)
減低代碼重復(fù)
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴(kuò)展類
函數(shù)–部分應(yīng)用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實(shí)現(xiàn)可疊加的修改操作

Trait 的基本概念

在 Scala中Trait 為重用代碼的一個基本單位。一個 Traits 封裝了方法和變量,和 Interface 相比,它的方法可以有實(shí)現(xiàn),這一點(diǎn)有點(diǎn)和抽象類定義類似。但和類繼承不同的是,Scala 中類繼承為單一繼承,也就是說子類只能有一個父類。當(dāng)一個類可以和多個 Trait 混合,這些 Trait 定義的成員變量和方法也就變成了該類的成員變量和方法,由此可以看出 Trait 集合了 Interface 和抽象類的優(yōu)點(diǎn),同時又沒有破壞單一繼承的原則。

下面我們來看看Trait的基本用法:

定義一個 Trait 的方法和定義一個類的方法非常類似,除了它使用 trait 而非 class 關(guān)鍵字來定義一個 trait。

trait Philosophical{
  def philosophize() {
    println("I consume memeory, therefor I am!")
  }
}

這個 Trait 名為 Philosophical。它沒有聲明基類,因此和類一樣,有個缺省的基類 AnyRef。它定義了一個方法,叫做 philosophize。這是個簡單的 Trait,僅夠說明 Trait 如何工作。

一但定義好 Trait,它就可以用來和一個類混合,這可以使用 extends 或 with 來混合一個 trait。例如:

class Frog extends Philosophical{
  override def toString="gree"
}

這里我們使用 extends 為 Frog 添加 Philosophical Trait 屬性,因此 Frog 缺省繼承自 Philosophical 的父類 AnyRef,這樣 Frog 類也具有了 Philosophical 的性質(zhì)(因此 Trait 也可以翻譯成特質(zhì),但后面我們還是繼續(xù)使用 Trait 原文)。

scala> val frog = new Frog
frog: Frog = green
scala> frog.philosophize
I consume memeory, therefor I am!

可以看到 Frog 添加了 Philosophical(哲學(xué)性)也具有了哲學(xué)家的特性,可以說出類似“我思故我在”的話語了。和 Interface 一樣,Trait 也定義一個類型,比如:

scala> val phil:Philosophical = frog
phil: Philosophical = green
scala> phil.philosophize
I consume memeory, therefor I am!

變量 phil 的類型為 Philosophical。

如果你需要把某個 Trait 添加到一個有基類的子類中,使用 extends 繼承基類,而可以通過 with 添加 Trait。比如:

class Animal
class Frog extends Animal with Philosophical{
  override def toString="green"
}

還是和 Interface 類似,可以為某個類添加多個 Trait 屬性,此時使用多個 with 即可,比如:

class Animal
trait HasLegs 
class Frog extends Animal with Philosophical with HasLegs{
  override def toString="green"
}

目前為止你看到的例子中,類 Frog 都繼承了 Philosophical 的 philosophize 實(shí)現(xiàn)。此外 Frog 也可以重載 philosophize 方法。語法與重載基類中定義的方法一樣。

class Animal
trait HasLegs 
class Frog extends Animal with Philosophical with HasLegs{
  override def toString="green"
  def philosophize() {
    println("It ain't easy being " + toString + "!")
  }
}

因?yàn)?Frog 的這個新定義仍然混入了特質(zhì) Philosophize,你仍然可以把它當(dāng)作這種類型的變量使用。但是由于 Frog 重載了 Philosophical 的 philosophize 實(shí)現(xiàn),當(dāng)你調(diào)用它的時候,你會得到新的回應(yīng):

scala> val phrog:Philosophical = new Frog
phrog: Philosophical = green
scala> phrog.philosophize
It ain't easy being green!

這時你或許推導(dǎo)出以下結(jié)論:Trait 就像是帶有具體方法的 Java 接口,不過其實(shí)它能做的更多。Trait 可以,比方說,聲明字段和維持狀態(tài)值。實(shí)際上,你可以用 Trait 定義做任何用類定義做的事,并且語法也是一樣的,除了兩點(diǎn)。第一點(diǎn),Trait 不能有任何“類”參數(shù),也就是說,傳遞給類的主構(gòu)造器的參數(shù)。換句話說,盡管你可以定義如下的類:

class Point(x: Int, y: Int)

但下面的 Trait 定義直接報錯:

scala> trait NoPoint(x:Int,y:Int)
<console>:1: error: traits or objects may not have parameters
       trait NoPoint(x:Int,y:Int)