scala之使用子类的类型实现特征方法

davidwang456 阅读:87 2025-06-02 22:19:02 评论:0

我想要一个特征 Foo 来提供 transform 方法来应用一个函数。另外,我想强制实现类具有 increment 方法,该方法也会以某种方式转换对象。天真的解决方案:

trait Foo { 
  def transform(fun: Foo => Foo): Foo = fun(this) 
  def increment(n: Int): Foo 
} 
 
case class A(a: Int) extends Foo { 
  // expecting available: transform(fun: A => A): A 
  // to be implemented: increment(n: Int): A 
  ... 
} 

以上行不通...继承的 transform 仍然需要 Foo => Foo,而不是 A => A increment 仍然想要返回 Foo,而不是 A

再试一次:

trait Foo { 
  def transform[C <: Foo](fun: C => C): C = fun(this.asInstanceOf[C]) 
  def increment[C <: Foo](n: Int): C 
} 
 
case class A(a: Int) extends Foo { 
  def increment(n: Int) = A(a + n) 
} 

A 不会编译 - 它仍然会提示签名。

取出 increment 函数,变换就可以了。然而 asInstanceOf 看起来有点不安全。此外,我需要显式提供类型参数给 transform:

val a = A(1) 
a.transform[A](x => x.copy(x.a + 1)) // returns A(2) 

我想知道是否有一种聪明的方法来完成它。

请您参考如下方法:

获得所需内容的最直接方法是将类型参数移至特征声明。这给出了 trait Foo[C]{...}。但是,在您的 transform 中使用 copy 仍然不起作用,因为 Foo 特性对任何扩展它的东西一无所知。您可以使用 self typing 提供更多信息。 :

trait Foo[C] { 
  this: C => 
    def transform(fun: C => C): C = fun(this) 
    def increment(n: Int): C 
} 
 
case class A(a: Int) extends Foo[A] { 
  def increment(n: Int) = A(a + n) 
} 

A extends Foo[A] 在这里使用起来有点笨拙,但它确实有效,因为现在当您扩展 Foo 时,它会将该类型信息返回给特质。但这仍然有点尴尬。原来有一种技术叫做type classes我们可以在这里使用它来潜在地改进事情。首先,你设置你的特质。在一个类型类中,每个类型只有一个 trait 的实现,所以每个方法也应该接受你想要操作的实例:

trait Foo[C] { 
  def transform(c: C)(f: C => C): C 
  def increment(c: C, inc: Int): C 
} 

接下来,在伴随对象中为您关心的类型设置类型类的实例:

case class A(a: Int) 
 
object Foo { 
  implicit val ATransform = new Foo[A] { 
    def transform (base: A)(f: A => A) = f(base) 
    def increment(base: A, inc: Int) = A(base.a+inc) 
  } 
 
  //Convenience function for finding the instance for a type. 
  //With this, Foo[A] is equivalent to implicitly[Foo[A]] 
  def apply[C](implicit foo: Foo[C]) = foo 
} 

现在我们可以使用类型类如下:

val b = A(3) 
Foo[A].transform(b)(x=>x.copy(a=x.a+1)) //A(4) 
Foo[A].increment(b,5) //A(8) 


标签:Scala
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号