函数根据参数的类型返回特定的特征子类

时间:2015-05-13 02:46:34

标签: scala

我有以下内容:

trait Foo {def x: Int}
case class Blah(x: Int) extends Foo
case class Bar(x: Int) extends Foo

我注意到我们有很多这样的隐式类:

implicit class FooTransformer(value: X) extends AnyVal {
  def toFoo: Foo = Blah(value)
}

在这种情况下,使用Blah而不是Bar取决于 value X 的事实。在我看来,能够做到这一点真是太好了:

implicit class FooTransformer[T](value: T) extends AnyVal {
  def toFoo: Foo = Something(value)
}

但我遇到的问题是如何将T映射到Something。我正在思考这些问题:

def apply[T](value: T): Foo = {
  value match {
    case x: Int => Blah(x)
    case z: String => Bar(z)
  }
}

但问题在于我得到的类型不匹配,期待 Foo 并得到 Bar 。这感觉它必须是一个可解决的问题,但我现在卡住了。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

首先,x必须是通用的或类型字段,因为它可以是IntString

其次,你无法避免定义转换函数,因为如果你有一个像上面所写的函数(不编译):

def apply[T](value: T): Foo = {
  value match {
    case x: Int => Blah(x)
    case z: String => Bar(z)
  }
}

然后Scala在TString之间没有Int的通用类型。要解决这个问题,你需要将它分成多个函数,因此你需要某种方式来暗示。

这是一个比你使用已经定义的apply函数更短的版本,它只是使它们隐含在案例类中:

trait Foo[T] {
  def x : T
}

case class Blah(x: String) extends Foo[String]

case class Bar(x: Int) extends Foo[Int]

object TryApp extends App {

  implicit def toBlah = Blah.apply _
  implicit def toBar = Bar.apply _

  def test[T](smth: Foo[T]): Unit = println(smth)

  test(1)
  test("str")
  // does not compile: test(2.2)
}

magnet pattern的另一种类似方式:

trait Foo {
  type Result
  def x: Result
}

case class Blah(x: String) extends Foo { type Result = String }

case class Bar(x: Int) extends Foo { type Result = Int }


object TryApp extends App {

  implicit def fromString(value: String) = Blah(value)

  implicit def fromInt(value: Int) = Bar(value)

  def test(magnet: Foo): Unit = println(magnet)

  test(1)
  test("str")
  // does not compile: test(2.2)
}

在所有2种情况下打印:

Bar(1)
Blah(str)