在很多語言中做一件簡單的事情,但在Scala中沒有做的事情是:在Scala中,如何對伴隨對象執行編譯時類型檢查?
定義原型'超級',這樣'超級'的所有實現都必須定義一個構造函數'create()'。
我發現這個約束非常重要,能夠在運行前識別很多問題。然而,這個特性只在Java中部分強制執行(通過定義一個總是拋出錯誤的'抽象'靜態方法),並且在Scala中完全缺失(伴隨對象完全脫離類並且不能在原型中強制執行)。
有沒有一個宏或工具,允許我這樣做?
UPDATE對不起,我的問題缺少上下文和示例。這裏是一個正式的用例中階:
在項目中,我們定義了可以被所有的子項目進行擴展接口:
trait AbstractFoo {}
這個接口應該始終有一個默認的0參數的構造/構造,所以項目A可以初始化點播,但是,每一個構造函數的實現是未知的項目答:
object AbstractFoo {
def default[T <: AbstractFoo: ClassTag](): T
}
所以,問題就變成了:如何嚴格地定義AbstractFoo,使得對A,任何的各子項目AbstractFoo的實現:
case class Foo(...) extends AbstractFoo
必須滿足:
'富' 必須定義(大概在其同伴對象)0-參數助洗劑/構造
主叫AbstractFoo.defaultFoo可以調用此0 - 參數生成器/構造器
應該指出的是,條件下,溶液中存在,其是定義每一個同伴對象作爲隱式類型類:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
}
object AbstractFoo {
implicit object Foo extends FooBuilder[Foo] {
def default() = {...}
}
def default[T <: AbstractFoo: FooBuilder](): T = {
implicitly[FooBuilder[T]].default
}
}
使得如果隱式對象是未定義編譯器會給出一個隱式的未找到錯誤(我的代碼段可具有一些語法錯誤,這個想法來自http://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala)
不幸的是,這並不總是很方便,因爲A的這個子項目通常對項目A是未知的。然而,默認的隱式構建器不能被重新定義,這使得每個default()調用都更加複雜。
我相信scala是一種非常易於擴展的語言,所以無論使用宏,註釋還是其他元編程技術,至少應該有一種方法來執行它。我的問題現在清楚了嗎?
UPDATE2:我相信我發現後的解決方案仔細研究Scaladoc,還有隱藏在角落裏的註釋:
如果有匹配的隱含參數的類型,最具體的人會這幾個符合條件的參數使用靜態重載分辨率的規則(見Scala的規範§6.26.4)來選擇:
...
的類型參數隱範圍(2.8.0)
...
因此,所有我需要的是寫FooBuilder的隱函數:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
implicit def self = this
}
object Foo extends FooBuilder[Foo]
所以每次有人叫:
default[Foo]
斯卡拉將引用類的範圍Foo包含對象Foo,它包含隱式值Foo,並最終找到0參數構造函數。
我認爲這個定義比在對象FooBuilder中定義它要好,因爲你只能定義一次FooBuilder,因此它不是可擴展的。你會同意我嗎?如果是這樣,你能否修改你的答案,以便我可以授予你的觀點?
我不認爲'抽象'靜態方法是Java中的一件事情。靜態方法不能被覆蓋。 –
歐普是如此無知,但他確信他說的有點有趣...我不知道他是否在嘲弄 –
不,這是一個合理的問題(請參閱@Wheaties的回答中的評論) – Phasmid