我有以下内容:
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 。这感觉它必须是一个可解决的问题,但我现在卡住了。有什么想法吗?
答案 0 :(得分:0)
首先,x
必须是通用的或类型字段,因为它可以是Int
或String
。
其次,你无法避免定义转换函数,因为如果你有一个像上面所写的函数(不编译):
def apply[T](value: T): Foo = {
value match {
case x: Int => Blah(x)
case z: String => Bar(z)
}
}
然后Scala在T
和String
之间没有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)