为什么使用类型变量使这段代码有效

时间:2017-05-31 15:54:12

标签: scala

这有效

trait SomeTrait {   
  type T   
 def write2( s: String): T 
}

case class C() extends SomeTrait {  
  type T = String   
  override  def write2(s:String): T = s }

但这不是

trait SomeTrait {  
  def write2[T]( s: String): T 
}

case class C() extends SomeTrait {   
 override  def write2(s: String): String =s }

根据我的推理,他们看起来很相似。为什么编译器特别指出“方法不会覆盖任何东西”错误?有没有办法使这项工作?

3 个答案:

答案 0 :(得分:3)

第二个代码段中的特征定义并不意味着它的实现必须对某些类型p具有方法q,但它必须具有方法write2类型参数T

这意味着,如果您有一个值write2,那么您应该可以

T

答案 1 :(得分:3)

如果您使用此定义:

trait T {  
  def write2[T]( s: String): T 
}

考虑一些使用此特征的客户。例如:

def doSomething(t: T): Unit = {
  val s: String = t.write2[String]("hello")
  val n: Int = t.write2[Int]("world")
  val d: Double = t.write2[Double]("!")
  println(s + n.toString + d.toString)
}

我不知道s,n和d的值是什么,但从理论上讲,从编译器的角度来看,这将是一个完美有效的特性用法。因此,为了真正覆盖write2[T]方法,您必须为所有可能类型T提供有效行为。

将其与:

进行比较
trait T2 {   
  type T   
  def write2( s: String): T 
}

甚至:

trait T3[T] {
  def write2(s: String): T
}

然后当呼叫者使用它时:

def doSomething(t: T2): Unit = {
  val x = t.write2("hello") // always returns type t.T
}

def doSomething[T](t: T3[T]): Unit = {
  val x = t.write2("hello") // always returns type T
}

只有具有该特征的特定实例,才能返回一种可能的类型。因此,要覆盖该方法,您只需覆盖该类型的行为。

答案 2 :(得分:1)

编译:

trait T {
     def write2[T]( s: String): T
 }

 case class C() extends T {
     override  def write2[T](s: String): T =s.asInstanceOf[T]
 }

write2返回一个T,而不是String(因此你的第二个覆盖不起作用的原因以及上面代码中丑陋演员的必要性)