2016-09-24 60 views
1

考慮到這些類和變量:這是鑄造到子類型安全嗎?

abstract class Base[T <: Base[_]] { 
    val self: T 
    def me(): T = self 
} 

class Derived extends Base[Derived] { 
    lazy val self = this 
    def whoAmI() = "Im derived" 
} 

val d = new Derived 

我可以安全地調用d.foo().whoAmI()

但這樣做也是類型安全嗎?

abstract class Base[T <: Base[_]] { 
    def me(): T = this.asInstanceOf[T] 
} 

class Derived extends Base[Derived] { 
    def whoAmI() = "Im derived" 
} 

我考慮邊緣情況在其他類衍生自擴展和轉換可以炸燬

回答

5

它不是類型安全的。如果你發現你需要使用asInstanceOf來編譯它,那麼答案絕對是「不」。如果只有一個子類型,則唯一一次投射到子類型是「安全」的。否則,你不能作任何保證。

考慮這個例子:

abstract class Base[T <: Base[_]] { 
    def me(): T = this.asInstanceOf[T] 
} 

class A extends Base[A] 
class B extends Base[A] 

scala> val b = new B 
b: B = [email protected] 

scala> b.me 
java.lang.ClassCastException: B cannot be cast to A 
    ... 33 elided 

有在BaseT我們繼承必須是相同的,因爲我們正在創建的子類型沒有限制 - 只是他們都擴展BaseAB都是Base[_],但B不是A,因此投射到A將是不安全的。

這很容易通過在Base中引入自我類型來解決,這需要它也是T。然後,我們可以確定this是一個T並且不需要投射。

abstract class Base[T <: Base[_]] { this: T => 
    def me(): T = this 
} 

這將不再編譯:

scala> class B extends Base[A] 
<console>:12: error: illegal inheritance; 
self-type B does not conform to Base[A]'s selftype A 
     class B extends Base[A] 
        ^
+0

這非常有意義,謝謝 –