2013-01-14 67 views
18

我需要兩個實例可以訪問其他私人。我自然地想到一個伴侶對象,它允許訪問它的伴侶類的一個唯一的實例。這個類本身是私有的,所以用戶不能僅僅使用new來創建實例。伴侶對象到私人類:爲什麼它不是有效的?

object A { 
    def apply = dual 
    lazy val dual = new A 
} 

private class A { 
    //some irrelevant logic... 
} 

此代碼不能編譯。我得到:類A逃脫其定義範圍作爲類型A錯誤的一部分,我不明白。我目前的解決方法是定義一個特徵,該類應具有的每種方法聲明,並使class A擴展該特徵,而雙特徵屬於特徵類型,而不是class A類型。

我在這裏失蹤的理論問題是什麼?爲什麼這是禁止的?

+8

到每個人士兵 –

+2

呵呵呵訪問@ AK4749很好,畢竟這是她的同伴,我們正在談論。這不是像班級只允許_anyone_訪問她的私人...雖然_reflection _... –

回答

29

Paolo的解決方案很好(+1),但他沒有解釋錯誤信息,所以讓我試試看。問題源於每個方法都需要返回類型的事實。您的原始定義applydual返回了class A的對象,因此兩者的隱式返回類型爲A。這意味着A必須對客戶可見 - 他們還能如何調用該功能或​​訪問val?而且,因爲兩者都是公開的,所以它們是全球可見的。但是,您聲明A private這意味着它不能在其包裝外部可見。所以有一個編譯器無法解決的衝突。

一般規則是,函數/成員的所有參數和返回類型必須具有(至少)與引用成員本身*相同的可見性範圍。因此解決這個問題的一個微不足道的方法是將applydual的可視性降低到private。這將滿足編譯器,但不是你:-)

您的解決方案通過將靜態返回類型更改爲public特徵,從而具有與引用它的成員相同的可見性來解決此問題。返回對象的動態類型仍然是class A,但是,客戶端無需看到它。這是原理"program to interfaces, not implementations"的典型示例。

注意,這個原則適用於充分的程度,一個可以把class Aprivate內部類的object A,從而使其innaccessible即使是同一個包中的其它類:

trait A { 
    //... 
} 

object A { 
    def apply: A = dual 
    lazy val dual: A = new AImpl 

    private class AImpl extends A { 
     //some irrelevant logic... 
    } 

} 

* 要按照規範,封閉類/對象可以減少其部件的可見性,如這裏:

private class Holder { 
    def member = new Hidden 
} 

private class Hidden 

其中memberpublic,但其封閉類是private,有效地將其成員從外部世界隱藏起來。所以編譯器在這裏沒有投訴。

+0

這的確是一個很好的回答 –

+0

!一個非常好的答案..!謝謝! –

23

我認爲你不想要一個私人類,而是一個具有私人構造函數的類。

class A private() 
object A { 
    def apply = dual 
    lazy val dual = new A 
} 

現在你的類對外部代碼「可見」,但只有你的伴侶對象可以創建它的實例。

+0

謝謝!愚蠢的我......有時候,最令人費解的問題實際上有點愚蠢和簡單。 –

相關問題