2011-09-06 22 views
12

什麼可以在Scala中使用private final修飾符?使用斯卡拉的私人最終修飾符?

考慮下面的代碼:

1| class A { def callFoo = foo; private final def foo = "bar of A" } 
2| class B extends A { private final def foo = "bar of B"} 
3| println((new A()).callFoo) 
4| println((new B()).callFoo) 

3號線和4打印:

1| bar of A 
2| bar of A 

爲什麼2號線不打印bar of B,因爲實際上有兩個foo定義,而後者是可以理解的在B中不會覆蓋A中的前者,否則Scala將需要override - 而不是final修飾符。

那麼爲什麼斯卡拉不是簡單地禁止修飾符private final的組合?

回答

14

好的,這很棘手。你的問題:「那麼爲什麼Scala不會簡單地禁止修改器的私有組合?」基於這種組合沒有用處的假設。

假設你是對的(除了一個小細節外,你將會在後面提到)。我不是一個編譯器的人,但從我的角度來看,「簡單地禁止」可能不是那麼簡單(至少在這種情況下)。爲什麼有人會試圖做到這一點?什麼是取捨?只是因爲某些東西沒有用,並不一定意味着它會造成任何傷害。只是不要使用它...

現在來看看你忽略的細節。 private修飾符是一個可見性修飾符,這意味着class B不知道它的存在。但是,斯卡拉的可見性修飾符比Java說的要複雜一些。我們假設無論出於何種原因,您需要在以下代碼片段中顯示代碼,編譯器將不會允許它。

package scope 

class A { 
    def callFoo = foo; 
    private[scope] final def foo = "bar of A" 
} 
class B extends A { 
    private[scope] final def foo = "bar of B" 
} 

object Main extends App { 
    println((new A()).callFoo) 
    println((new B()).callFoo) 
} 

這是由編譯器所提供的錯誤之一:「方法foo不能覆蓋最終構件」

所以,你在這裏。斯卡拉簡單地禁止這個組合;)

+0

我沒有想到修改器可以具有的附加範圍。你是對的,有一個私人定義,'final'禁止覆蓋它。在這種情況下它有用處。但除此之外,我認爲沒有效果的語言結構一定不合法。在這裏,如果'final'不能阻止子類或特徵覆蓋定義,則不能在聲明中使用它。 –

+0

@Tim「final」的原因並不妨礙子類/特徵覆蓋定義是因爲'private'已經阻止了這個。 'private'成員對子類不可見,所以沒有什麼可以重寫。因爲這是一個問題,程序員必須犯兩個不同的錯誤:1)試圖重載一個私有方法,2)忘記使用'override'關鍵字。這在Java中是一樣的,因爲'@ Override'註釋是可選的,所以Java更容易出錯。 –

3

我最初以爲是防止嵌套類壓倒一切的私有方法,但顯然不是:

class A { 
    private final def foo = 0 

    class B extends A { 
    override def foo = 1 
    } 
} 

error: method foo overrides nothing 
      override def foo = 1 
         ^

也許這只是簡化重構?所以如果你有一個final的方法,試着把它做成private,並且覺得你需要的不是private畢竟你不會在這個過程中失去final

+1

+1「防止重構」點! –

3

解決更廣泛的問題,

那麼,爲什麼斯卡拉不是簡單地禁止修飾符 私人最終的組合?

這是一個新的規則,並且,在那個,一個新的例外。它使語言更加複雜,並且絕對沒有收穫。爲什麼沒有很好的理由讓事情變得更復雜?

這就是Odersky不喜歡的很多東西。要使語言變得更復雜,就必須有一些收益。

+2

解析器/編譯器的語言可能會變得更復雜,因爲它需要知道該異常。但從用戶的角度來看,我認爲在編譯器的指導下更容易。另一個例子是「抽象特質A」與「特質A」。當所有特徵都成立時,明確說明特定特徵是「抽象的」有什麼用處。 –

+0

@Tim您認爲用戶不需要_learn_ the _whole_語言嗎?畢竟,編譯器不僅需要支持該規則 - 程序員還必須學習它。 –