类型推断&斯卡拉的泛型

时间:2017-12-11 05:59:49

标签: scala

我正在执行以下函数从另一个函数返回一个新图形,但Scala将结果推断为图形,我希望它特别是图形,圆形等。 我怎么能推断这个特定的数字呢?我被告知使用泛型来解决它,这将是怎样的?

trait Figure {
  def x:Int
  def y:Int
}

case class Circle(x:Int, y: Int, radio: Double)
  extends Figure

case class Rectangle(x:Int, y: Int, width: Int, high: Int)
  extends Figure

object Motor {

  def move[T](x: Int, y: Int, figure: T) :Figure = figure match {
    case Circle(xPos, yPos, radio) => Circle(xPos+x, yPos+y, radio)          
    case Rectangle(xPos, yPos, width, high) => Rectangle(xPos+x, yPos+y, width, high)
  }
}

4 个答案:

答案 0 :(得分:2)

这是一个更简洁,也许是一个不那么令人生畏的版本的Sarvesh Kumar Singh使用类型类的建议。我认为这是最好的方法。它为您提供类型安全功能,同时让您保持基本类型非常简单。

trait Figure {
  def x:Int
  def y:Int
}
case class Circle(x:Int, y: Int, radius: Double) extends Figure

case class Rectangle(x:Int, y: Int, width: Int, height: Int) extends Figure

trait Movable[T] {
  def move( x: Int, y: Int, movable: T ) : T
}
implicit final object CircleIsMovable  extends Movable[Circle] {
  def move( x: Int, y: Int, c: Circle ) = Circle( c.x + x, c.y + y, c.radius )
}
implicit final object RectangleIsMovable  extends Movable[Rectangle] {
  def move( x: Int, y: Int, r: Rectangle ) = Rectangle( r.x + x, r.y + y, r.width, r.height )
}
object Motor {
  def move[T : Movable](x: Int, y: Int, movable: T) : T = implicitly[Movable[T]].move( x, y, movable )
}

则...

scala> Motor.move(10,10,Circle(0,0,1))
res1: Circle = Circle(10,10,1.0)

scala> Motor.move(10,10,Rectangle(0,0,1,1))
res2: Rectangle = Rectangle(10,10,1,1)

答案 1 :(得分:1)

您应该这样做,以便"move" type本身T发生,并返回type T。但是编译器会抱怨你不确定是否返回T因为T的实际类型将被确定为使用move而编译器没有证据确定它是Circlematch-case是运行时的东西。

这意味着您需要提供可以在编译时使用move任何type T实例的证据。

import scala.language.implicitConversions

trait Figure {
  def x:Int
  def y:Int
}

case class Circle(x:Int, y: Int, radio: Double)
  extends Figure

case class Rectangle(x:Int, y: Int, width: Int, high: Int)
  extends Figure

现在,让我们构建所需的证据,用于“丰富”我们的Figure实例

trait MoveSupport[F <: Figure] {
  val f: F
  def move(x: Int, y: Int): F
}

object MoveSupport {

  class CircleMoveSupport(val f: Circle) extends MoveSupport[Circle] {
    override def move(x: Int, y: Int): Circle = f.copy(x = f.x + x, y = f.y + y)
  }

  class RectangleMoveSupport(val f: Rectangle) extends MoveSupport[Rectangle] {
    override def move(x: Int, y: Int): Rectangle = f.copy(x = f.x + x, y = f.y + y)
  }

  implicit def toCircleMoveSupport(circle: Circle) = new CircleMoveSupport(circle)

  implicit def toRectangleMoveSupport(rectangle: Rectangle) = new RectangleMoveSupport(rectangle)

}

现在,我们可以使用这些证据“丰富”我们的Figure类型以获得move支持。

import MoveSupport._ 

val circle = Circle(1, 1, 1)
// circle: Circle = Circle(1,1,1.0)

val circle2 = circle.move(1, 1)
// circle2: Circle = Circle(2,2,1.0)

或者,您可以使用这些证据构建Motor

object Motor {
  import MoveSupport._

  def move[T <: Figure](x: Int, y: Int, figure: T)(implicit ev: T => MoveSupport[T]): T = figure.move(x, y)

}

val c = Circle(1, 1, 1)
// circle: Circle = Circle(1,1,1.0)    

val c1 = Motor.move(1, 1, c) 
// circle1: Circle = Circle(2,2,1.0)

答案 2 :(得分:0)

也许你所追求的是

object Motor {
  def move[T <: Figure](x: Int, y: Int, figure: T): T = {
    val moved = figure match {
      case Circle(xPos, yPos, radio) => Circle(xPos+x, yPos+y, radio)          
      case Rectangle(xPos, yPos, width, high) => Rectangle(xPos+x, yPos+y, width, high)
    }
    moved.asInstanceOf[T]
  }
}

答案 3 :(得分:0)

您可能需要考虑将move的实现移动到各个类。下面是一个使用abstract types来使该方法返回对象类型的示例:

trait Figure {
  def x: Int
  def y: Int

  type Self <: Figure
  def move(dx: Int, dy: Int): Self
}

case class Circle(x: Int, y: Int, radius: Double) extends Figure {
  type Self = Circle
  def move(dx: Int, dy: Int): Circle = copy(x = x + dx, y = y + dy)
}

case class Rectangle(x: Int, y: Int, widht: Int, height: Int) extends Figure {
  type Self = Rectangle
  def move(dx: Int, dy: Int): Rectangle = copy(x = x + dx, y = y + dy)
}