2014-10-05 38 views
0

爲了定義MyInt這個片段中唯一的類,我將下面的原始代碼從使用案例類更改爲普通類。在沒有編譯失敗的情況下將案例類重構爲非案例類

trait Similar { 
    def isSimilar(x: Any): Boolean 
} 

class MyInt(x: Int) extends Similar { 
    def isSimilar(m: Any): Boolean = 
    m.isInstanceOf[MyInt] && 
    m.asInstanceOf[MyInt].x == x 
} 

object UpperBoundTest extends App { 
    def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean = 
    if (xs.isEmpty) false 
    else if (e.isSimilar(xs.head)) true 
    else findSimilar[T](e, xs.tail) 
    val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3)) 
    println(findSimilar[MyInt](MyInt(4), list)) 
    println(findSimilar[MyInt](MyInt(2), list)) 
} 

不再編譯

[error] 7: type mismatch; 
[error] found : MyInt 
[error] required: ?{def x: ?} 
[error] Note that implicit conversions are not applicable because they are ambiguous: 
[error] both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] 
[error] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] 
[error] are possible conversion functions from MyInt to ?{def x: ?} 
[error]  m.asInstanceOf[MyInt].x == x 
[error]     ^

這是一個有趣的案例給我,因爲有時我發現自己重構case類爲普通類,而重構繼承,需要在以做顯然有些變化代碼以便享受保持代碼正常工作的平穩過渡。

.AsInstanceOf切換爲等效匹配(m match {case m:MyInt => m.x == x; case _ => false})會產生相同的編譯錯誤。使用比較幼稚的比賽不會編譯之一:

trait Similar { 
    def isSimilar(x: Any): Boolean 
} 

class MyInt(x: Int) extends Similar { 
    def isSimilar(m: Any): Boolean = { 
    m match {case m:MyInt => true; case _ => false} 
    } 
} 

object UpperBoundTest extends App { 
    val a = new MyInt(4) 
    def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean = 
    if (xs.isEmpty) false 
    else if (e.isSimilar(xs.head)) true 
    else findSimilar[T](e, xs.tail) 
    val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3)) 
    println(findSimilar[MyInt](MyInt(4), list)) 
    println(findSimilar[MyInt](MyInt(2), list)) 
} 

18: not found: value MyInt 
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3)) 
[error]        ^
18: not found: value MyInt 
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3)) 
[error]          ^
18: not found: value MyInt 
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3)) 
[error]             ^
19: not found: value MyInt 
[error] println(findSimilar[MyInt](MyInt(4), list)) 
[error]       ^
20: not found: value MyInt 
[error] println(findSimilar[MyInt](MyInt(2), list)) 
[error]       ^
[error] 5 errors found 

是非case類的一個練習,不是利用他們的繼承他們被enitrely勸阻其他,或當你將永遠需要檢查他們的類型?你什麼時候會使用非案例類?

回答

4

簡單地聲明你的類作爲

class MyInt(val x: Int) extends Similar 

對於case類val是默認的,而在普通班,你需要明確地將它添加到的信號要合成的訪問器構造函數的參數

另外,如果類別中提供默認應用方法的伴侶對象自動合成,允許您撥打

MyInt(2) 

而不是

new MyInt(2) 

您必須使用後者,或手動在伴隨對象中提供apply方法。

底線,如果你需要匹配的一類,案例類是方便多了,因爲你可以跳過喪氣(這是隱式執行,當你的類型做x: MyInt匹配)

類是不灰心,只要情況下,類在具體使用更方便 - 案例

+0

我還可以匹配,即使它不是個例類的類? – matanster 2014-10-05 11:54:24

+0

@matt是的,你只需要提供一個'unapply'方法。 – 2014-10-05 12:21:32

2

你需要避免在任何情況下編譯失敗,包括模式匹配完整代碼:

class MyInt(val x: Int) extends Similar 

object MyInt { 
    def apply(x: Int) = new MyInt(x) 

    // if more than one field, return Some(tuple of all fields) 
    def unapply(myInt: MyInt): Option[Int] = Some(myInt.x) 
} 

如果你也想BEHA vior是保持原來的,你需要定義equalshashCode方法,以及:

class MyInt(val x: Int) extends Similar { 
    def equals(y: Any) = y match { 
    case MyInt(z) => x == z 
    case _ => false 
    } 

    def hashCode = x 
}