鍍金池/ 教程/ Scala/ 組合和繼承–定義無參數(shù)方法
包對(duì)象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達(dá)式
類和對(duì)象 (三)
操作基本數(shù)據(jù)類型
for 表達(dá)式
組合和繼承–重載成員函數(shù)和方法
類和對(duì)象 (二)
組合和繼承–定義 factory 對(duì)象
組合和繼承–多態(tài)和動(dòng)態(tài)綁定
Trait 的基本概念
if 表達(dá)式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對(duì)象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對(duì)象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實(shí)現(xiàn)方法
try 表達(dá)式處理異常
選擇瘦接口還是胖接口設(shè)計(jì)?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對(duì)象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進(jìn)一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實(shí)現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對(duì)象 (四)
函數(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)可疊加的修改操作

組合和繼承–定義無參數(shù)方法

作為下一步,我們將向 Element 添加顯示寬度和高度的方法,height 方法返回 contents 里的行數(shù)。width 方法返回第一行的長度,或如果元素沒有行記錄,返回零。

abstract class Element { 
  def contents: Array[String] 
  def height: Int = contents.length 
  def width: Int = if (height == 0) 0 else contents(0).length 
}

請注意 Element 的三個(gè)方法沒一個(gè)有參數(shù)列表,甚至連個(gè)空列表都沒有,這種無參數(shù)方法在 Scala 里是非常普通的。相對(duì)的,帶有空括號(hào)的方法定義,如 def height(): Int,被稱為空括號(hào)方法:(empty-paren method)。

Scala的慣例是在方法不需要參數(shù)并且只是讀取對(duì)象狀態(tài)時(shí)使用無參數(shù)方法。

此外,我們也可以使用成員變量來定義 width 和 height,例如:

abstract class Element { 
  def contents: Array[String] 
  val height = contents.length 
  val width = if (height == 0) 0 else contents(0).length 
}

從使用這個(gè)類的客戶代碼來說,這兩個(gè)實(shí)現(xiàn)是等價(jià)的,唯一的差別是使用成員變量的方法調(diào)用速度要快些,因?yàn)樽侄沃翟陬惐怀跏蓟臅r(shí)候被預(yù)計(jì)算,而方法調(diào)用在每次調(diào)用的時(shí)候都要計(jì)算。換句話說,字段在每個(gè) Element 對(duì)象上需要更多的內(nèi)存空間。

特別是如果類的字段變成了訪問函數(shù),且訪問函數(shù)是純函數(shù)的,就是說它沒有副作用并且不依賴于可變狀態(tài),那么類 Element 的客戶不需要被重寫。這稱為統(tǒng)一訪問原則: uniform access principle, 就是說客戶代碼不應(yīng)受通過字段還是方法實(shí)現(xiàn)屬性的決定的影響。

Scala 代碼可以調(diào)用 Java 函數(shù)和類,而 Java 沒有使用“統(tǒng)一訪問原則”,因此 Java 里是 string.length(),不是 string.length。為了解決這個(gè)問題,Scala 對(duì)于無參數(shù)函數(shù)和空括號(hào)函數(shù)的使用上并不是區(qū)分得很嚴(yán)格。也就是,你可以用空括號(hào)方法重載無參數(shù)方法,并且反之亦可。你還可以在調(diào)用任何不帶參數(shù)的方法時(shí)省略空的括號(hào)。例如,下面兩行在 Scala里都是合法的:

Array(1, 2, 3).toString 
"abc".length

原則上 Scala 的函數(shù)調(diào)用中可以省略所有的空括號(hào)。但如果使用的函數(shù)不是純函數(shù),也就是說這個(gè)不帶參數(shù)的函數(shù)可能修改對(duì)象的狀態(tài)或是我們需要利用它的一些副作用(比如打印到屏幕,讀寫 I/o),一般的建議還是使用空括號(hào),比如:

"hello".length // 沒有副作用,所以無須() 
println() // 最好別省略()

總結(jié)起來,Scala 里定義不帶參數(shù)也沒有副作用的方法為無參數(shù)方法,也就是說,省略空的括號(hào),是鼓勵(lì)的風(fēng)格。另一方面,永遠(yuǎn)不要定義沒有括號(hào)的帶副作用的方法,因?yàn)槟菢拥脑挿椒ㄕ{(diào)用看上去會(huì)像選擇一個(gè)字段。