在下面的例子中,我希望能够使用一个隐式类型类- Process -将trait作为输入。但是编译器不能识别这种情况下的任何隐式。我期望Input是一个密封trait,并且我为InputA和InputB都做了隐式实现,在运行时它会根据提供的类型自行选择。
sealed trait Input
final case class InputA(i: Int) extends Input
final case class InputB(s: String) extends Input
trait Process[U] {
def give(u :U): U
}
object Process {
implicit val processInputA: Process[InputA] = (u: InputA) => u.copy(i = u.i+10)
implicit val processInputB: Process[InputB] = (u: InputB) => u.copy(s = u.s+"add")
}
object UseProcess {
def run[U](u: U)(implicit process: Process[U]): U = process.give(u)
}
val g: Input = InputB("1")
val res3: Input = UseProcess.run(g). ==>> No implicits found for parameter process: Process[Input]
有没有办法让它工作或者类型类只在具体类型上实现的情况下工作。
提前感谢您的回答
2条答案
按热度按时间owfi6suc1#
这不是特质与阶级的问题。
您正在调用的方法如下所示
为了调用,编译器需要在作用域中的某个地方找到
Process[Input]
类型的隐式示例,但实际上并没有。注意,
Process[InputB]
不是Process[Input]
的子类,因为Process
的参数是不变的,你可以试着让它像trait Process[+U]
一样协变......但在这种情况下不起作用,因为函数参数是逆变的(如果U
是协变的,就不能有give(u: U)
)。如果你能让你的特质协变,它仍然不会起作用,因为现在 *
processInputA
和processInputB
都适合,所以解决方案将是模糊的。基本上,在
g: Input
上转换到Input
是个坏主意,如果你想写一个函数来使用trait进行抽象,你应该参数化它:这应该行得通。
8e2ybdfx2#
我期待
Input
是一个密封的特征,我为InputA
和InputB
做了隐式实现,在运行时它根据提供的类型自行选择。隐式(类型类的示例)在编译时(而不是运行时)、类型检查(编译phase
typer
)期间解决。Runtime vs. Compile time
在
val g: Input = InputB("1")
中,只有在运行时才知道g
是InputB
而不是InputA
,在编译时才知道g
是Input
。因此,要么让编译器在编译时知道
g
是InputB
或为
Input
定义type类的示例正如你所看到的,如果你的逻辑是基于一个运行时值的,你需要模式匹配(大多发生在运行时)而不是隐式(类型类)解析,隐式(类型类)是一种编译时的“模式匹配”。
您还可以基于示例
Process[InputA]
、Process[InputB]
* 派生 * 示例Process[Input]
,而不是为每个sealed-trait层次结构手动定义它。Use the lowest subtype in a typeclass?