在不失败编译的情况下将案例类重构为非案例类

时间:2014-10-05 11:08:15

标签: scala

摆弄sample code demonstrating type bounds,我将下面的原始代码从使用case类更改为普通类,用于定义类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

除了使用非案例类继承它们,或者你永远不需要检查它们的类型时,是否真的不鼓励这种做法?你何时会使用非案例类?

2 个答案:

答案 0 :(得分:4)

只需将您的课程声明为

即可
class MyInt(val x: Int) extends Similar

对于案例类val是默认值,而在常规类中,您需要明确地将其添加到您想要合成构造函数参数的访问器的信号

此外,在案例类中,自动合成提供默认应用方法的伴随对象,允许您调用

MyInt(2)

而不是

new MyInt(2)

您必须使用后者,或在配对对象中手动提供apply方法。

最重要的是,如果你需要匹配一个类,case类就更方便了,因为你可以跳过downcast(当你在做x: MyInt的类型上匹配时隐式执行)

不鼓励使用类,只是在特定的用例中使用case-classes更方便

答案 1 :(得分: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)
}

如果您还希望行为与原始行为相同,则还需要定义equalshashCode方法:

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

  def hashCode = x
}