首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Scala特征中使用self类型作为返回类型

在Scala特征中使用self类型作为返回类型
EN

Stack Overflow用户
提问于 2019-07-25 18:55:09
回答 2查看 251关注 0票数 1

我想定义一个特征,它使用具体类的类型,在它的一个抽象方法中将其扩展为返回类型。这在Scala (2.13)中是可能的吗?例如,下面的代码无法编译,因为我找不到绑定ConcreteType的方法

代码语言:javascript
复制
trait Shape
trait Growable {
  def grow() : ConcreteType
}
case class Circle(x : Int, y : Int, size : Int) extends Shape with Growable {
  def grow() : Circle = this.copy(size = size + 1)
}
case class Square(x : Int, y : Int, size : Int) extends Shape with Growable {
  def grow() : Square = this.copy(size = size + 1)
}

我用下面的代码实现了一些类似的功能:

代码语言:javascript
复制
trait Shape
trait Growable[T <: Shape] {
  def grow() : T
}
case class Circle(x : Int, y : Int, size : Int) extends Shape with Growable[Circle] {
  def grow() : Circle = this.copy(size = size + 1)
}
case class Square(x : Int, y : Int, size : Int) extends Shape with Growable[Square] {
  def grow() : Square = this.copy(size = size + 1)
}

然后,此代码的用户将像这样使用它:

代码语言:javascript
复制
val circle : Circle = Circle(0, 0, 10).grow()
val square : Square = Square(0, 0, 10).grow()
// or
val shapes : Seq[Shape] = List(circle, square).map(_.grow())

我希望避免必须通过泛型传递类型,这似乎是多余的。对于如何实现这一点有什么想法吗?

EN

回答 2

Stack Overflow用户

发布于 2019-07-25 19:28:05

考虑shapeless lenses方法

代码语言:javascript
复制
import shapeless._

sealed trait Shape
case class Circle(x : Int, y : Int, size : Int) extends Shape
case class Square(x : Int, y : Int, size : Int) extends Shape

implicit val circleLens = lens[Circle].size
implicit val squareLens = lens[Square].size

implicit class GrowableShape[T <: Shape](shape: T) {
  def grow()(implicit shapeLense: Lens[T, Int]): T =
    shapeLense.modify(shape)(_ + 1)
}

Circle(0, 0, 10).grow()
Square(0, 0, 10).grow()

哪种输出

代码语言:javascript
复制
res0: Circle = Circle(0,0,11)
res1: Square = Square(0,0,11)

或者,考虑使用vanilla scala的类型类解决方案

代码语言:javascript
复制
trait Growable[T <: Shape] {
  def grow(shape: T): T
}

sealed trait Shape
case class Circle(x : Int, y : Int, size : Int) extends Shape
case class Square(x : Int, y : Int, size : Int) extends Shape

implicit val circleGrowable = new Growable[Circle] {
  def grow(shape: Circle): Circle = shape.copy(size = shape.size + 1)
}

implicit val squareGrowable = new Growable[Square] {
  def grow(shape: Square): Square = shape.copy(size = shape.size + 1)
}

implicit class GrowableShape[T <: Shape](shape: T) {
  def grow()(implicit growable: Growable[T]): T =
    growable.grow(shape)
}

Circle(0, 0, 10).grow()
Square(0, 0, 10).grow()

哪种输出

代码语言:javascript
复制
res0: Circle = Circle(0,0,11)
res1: Square = Square(0,0,11)
票数 2
EN

Stack Overflow用户

发布于 2019-07-25 19:47:24

在最简单的方式中,由于scala方法/函数结果类型本质上是协方差,即() => Growable() => Circle() => Square的超类型,您可以通过在实现中显式提供具体类型来简单地执行以下操作:

代码语言:javascript
复制
  trait Shape
  trait Growable {
    def grow() : Growable
  }
  case class Circle(x : Int, y : Int, size : Int) extends Shape with Growable {
    def grow() : Circle = this.copy(size = size + 1)
  }
  case class Square(x : Int, y : Int, size : Int) extends Shape with Growable {
    def grow() : Square = this.copy(size = size + 1)
  }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57200316

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档