3

當使用反射來使用路徑依賴類型時,即使我有匹配的「基礎類型」,我也會遇到類型不匹配錯誤。什麼是這些「非基礎類型」,爲什麼他們檢查而不是「基礎類型」?路徑依賴類型與「基礎類型」,哪些被檢查?

在下面的代碼中,我想compare方法只接受A的同類型子類作爲參數。錯誤在最後一行。

abstract class A(val a:Int) { 
    type Impl <: A 
    def compare(other:Impl) { 
    if(a==other.a) println("equal") else println("diff") 
    } 
} 
class B(a:Int) extends A(a) {type Impl = B} 

object Test { 
    def newInst(a: Int, className: String) = { 
    val constr = Class.forName(className).getConstructors()(0) 
    constr.newInstance(a.asInstanceOf[AnyRef]).asInstanceOf[A] 
    } 

    def main(args: Array[String]) { 
    val b1 = newInst(4, "B") 
    val b2 = newInst(5, "B") 
    b1.compare(b2) // type mismatch error here 
    } 
} 

在最後一行我得到這個錯誤:

error: type mismatch; 
found : b2.type (with underlying type A) 
required: b1.Impl 

由於B2的類型相同b1的類型(這是),我預計這不會產生錯誤。由於某些原因,這些路徑依賴類型在使用反射時與「基礎類型」不同。爲什麼?

如果我不使用反射,它的工作原理:

val b1 = new B(4) 
val b2 = new B(5) 
b1.compare(b2) // no errors 

(我需要在我的情況下,使用反射)。 newInst()可以使用反射將對象返回爲類「B」嗎?這會有幫助嗎?使用抽象類型時是否有類型擦除?

這是我發現的唯一參考文獻(on this forum)關於相同的錯誤,但它可能沒有關係。

+0

謝謝您的詢問!這真是奇怪,花了我一天的時間找到解決方法,最後看到你的帖子。 – 2013-04-14 18:20:13

回答

5

這與反射沒有任何關係。 b1b2的類型是A(因爲這是返回類型newInst)。要撥打b1.compare(b2)進行編譯,b2必須具有b1.Impl類型。編譯器只知道它是A的某個子類型,但它不知道哪一個。由於您無法通過A,其中某些子類型爲A是必需的,因此會出現錯誤。

在這個例子中

val b1 = new B(4) 
val b2 = new B(5) 
b1.compare(b2) // no errors 

兩個變量的類型爲BB#ImplB,所以一切typechecks。

+0

我只是想到了這一點。表達「基礎類型」有點令人誤解,但它實際上意味着「父類型」。理想情況下,我想將newInst的返回類型轉換爲「className」類,但看起來在Scala中不可能。 – Adrian 2011-02-03 07:07:20

5

I just figured that out too. The expression "underlying type" is a bit misleading, while it actually means "parent type". Ideally I would like to cast the return type of newInst to the class of "className" but that looks like it is not possible in Scala. "

這並不意味着「父類型」。這種類型確實是父母。基礎類型是指單一類型的拓寬。數字5的類型是單身;其基礎類型是Int。大多數人不會將Int稱爲「父類型」。 (儘管如此,它也是。)

至於這個問題,你可以投它。沒有什麼會阻礙你:scala不會和java不能。

def main(args: Array[String]) { 
    val b1 = newInst(4, "B") 
    val b2 = newInst(5, "B") 
    b1.compare(b2.asInstanceOf[b1.Impl]) 
} 
% scala Test 
diff 
+0

我的意思是在返回之前,在newInst()中強制返回值。由於我沒有可用的類型(我只有Class),所以我沒有辦法做到這一點。如果可能的話,類型檢查器將能夠在編譯時根據運行時值(className)推斷newInst()的類型 - 當然這是不可能的。我認爲這也澄清了「基礎類型」的含義。它是編譯時已知的最具體的類型,而運行時類型只是作爲object.type而已知我不確定「擴大單例」的含義。 b2不是單身人士。 – Adrian 2011-02-03 16:20:14