2017-08-08 56 views
0

當我嘗試編譯下面的代碼爲什麼隱式轉換不適用於第二個參數?

case class A(x: Int = 0) 

object Conversions { 
    case class Converter[T](c: T) { 
    def +[U](that: Converter[U]): String = "worked" 
    } 
    implicit def convert(c: A): Converter[A] = Converter[A](c) 
    implicit def convert(c: Int): Converter[Int] = Converter[Int](c) 
} 

object Main extends App { 
    import Conversions._ 
    val a: String = A() + A() 
    val b: String = 1 + A() // FAIL 
    val c: String = A() + 1 
    val d: Int = 1 + 1 
} 

我收到以下錯誤消息

error: type mismatch; found: A; required: String

是什麼IntA之間的差異,使表達b失敗,而ac通?我該如何編譯它?

回答

1

首先,Int已經具有另一個+方法,其中期望另一個Int並返回一個Int; 如果添加了類似的方法來A你會得到類似的故障:

case class A(x: Int = 0) { 
    // this would be similar to Int's plus operation: 
    def +(other: A): A = A(x + other.x) 
} 

// now these would behave "symmetrically": 
val a: A = A() + A() 
val b: String = 1 + A() // FAIL 
val c: String = A() + 1 // FAIL 
val d: Int = 1 + 1 

至於爲什麼這個事實使這個特定的失敗 - 這是棘手的,我認爲它與爲了把該編譯器試圖根據左右參數「選擇」正確的隱式轉換。

+0

但'A()'不是Int! –

+0

我沒有聲稱'A'是一個'Int' - 我只是表明如果''''像'Int',有一個二元運算符叫'+' - 他們會表現得很相似。 –

+0

是的,但這第二次失敗可能有不同的機制。我已經創建了一個代碼版本,其中沒有第二個重載「Int。+(Int)」,但它仍然沒有編譯。要麼我犯了一個錯誤,要麼你的解釋是錯誤的。 –

0

如果更換算術+運營商,說plus

def plus[U](that: Converter[U]): String = "worked" 

你的隱式轉換應該工作,你所期望的方式:

val a = A() plus A() // worked 
val b = 1 plus A() // worked 
val c = A() plus 1 // worked 
val d = 1 plus 1  // worked 

不是IntA之間的直接隱式轉換,您的隱式轉換在IntConverter之間(以及A和之間)。編譯器顯然是有一個很難通過IntA之間的轉換規則排序時,看到對於Int良好限定一個+方法 - 除非你提供IntA像在下面的例子之間的直接的隱式轉換:

object A { 
    implicit def intToA(n: Int): A = A(n) 
} 

case class A(x: Int = 0) { 
    def +(that: A): A = A(this.x + that.x) 
} 

val a = A(1) + A(2) // A(3) 
val b = 1 + A(1)  // A(2) 
val c = A() + 1  // A(1) 
val d = 1 + 1  // 2 
+0

'A'和'Int'都不在我的書架中。我無法將'Int'轉換爲'A'。 –

0

我對這次嘗試成功的原因並不清楚,但我希望它對其他用戶有用。在這裏,我同時在兩個參數上進行匹配,以最大限度地減少Scala試圖強制隱式轉換的正確樹。

object Defs { 
    case class A(x: Int = 1) 
    case class B(x: Int = 2) 

    trait IsExpr[T] { 
     def conv(v: T): Int 
    } 

    implicit object aIsExpr extends IsExpr[A] { 
     override def conv(v: A): Int = v.x 
    } 

    implicit object bIsExpr extends IsExpr[B] { 
     override def conv(v: B): Int = v.x 
    } 

    implicit def canSum1[A, B](a: A, b: B)(implicit ca: IsExpr[A], cb: IsExpr[B]): Int = ca.conv(a) + cb.conv(b) 
    implicit def canSum2[A](a: A, b: Int)(implicit ca: IsExpr[A]): Int = ca.conv(a) + b 
    implicit def canSum3[A](a: Int, b: A)(implicit ca: IsExpr[A]): Int = a + ca.conv(b) 

    implicit def convert[A](a: A) = new { 
     def +[B](b: B)(implicit f: (A, B) => Int): Int = f(a, b) 
    } 
} 

object Main extends App { 
    import Defs._ 
    val a: Int = A() + A() 
    val b: Int = 1 + A() 
    val c: Int = A() + 1 
    val d: Int = 1 + 1 
} 
相關問題