gpt4 book ai didi

Scala:将逆变类型作为隐式参数传递不会选择最近的父类(super class)型?

转载 作者:行者123 更新时间:2023-12-04 23:12:41 28 4
gpt4 key购买 nike

为什么下面的代码没有选择最近父类(super class)型的隐式 val?

class A
class B extends A

trait TC[-T] { def show(t: T): String }

implicit val showA = new TC[A] { def show(a: A): String = "it's A" }
implicit val showB = new TC[B] { def show(b: B): String = "it's B" }

def doit[X](x: X)(implicit tc: TC[X]): Unit = println(tc.show(x))

doit(new A) // "it's A" as expected
doit(new B) // "it's A" ... why does this not give "it's B" ???

如果你让 TC不变的(即 trait TC[T] (...) ),然后它工作正常和 doit(new B)按预期返回“它是 B”。

通过为类型 Any 添加另一个隐式,这个问题就更极端了:
class A
class B extends A

trait TC[-T] { def show(t: T): String }

implicit val showA = new TC[A] { def show(a: A): String = "it's A" }
implicit val showB = new TC[B] { def show(b: B): String = "it's B" }
implicit val showAny = new TC[Any] { def show(x: Any): String = "it's Any" }

def doit[X](x: X)(implicit tc: TC[X]): Unit = println(tc.show(x))

doit(new A) // "it's Any" ... why does this not give "it's A" ???
doit(new B) // "it's Any" ... why does this not give "it's B" ???

如果 TC 也可以正常工作是不变的。

这是怎么回事,如何解决?
我的目标是有一个逆变 TC隐式地选择最接近的合适父类(super class)型。

最佳答案

TC[-T]在其类型参数中是逆变的,TC[A]TC[B] 的子类型,因此被认为更“具体”。这是一个众所周知(并且有些争议)的设计决策,这实质上意味着具有逆变的隐式解析有时会表现得非常出乎意料。

解决方法 1:使用继承优先化隐式

以下是如何使用继承和“LowPriority-*-Implicits”模式:

class A
class B extends A
class C extends B
class D extends C

trait TC[-T] { def show(t: T): String }

trait LowPriorityFallbackImplicits {
implicit def showA[X <: A]: TC[X] =
new TC[A] { def show(a: A): String = "it's A" }
}
object TcImplicits extends LowPriorityFallbackImplicits {
implicit def showC[X <: C]: TC[X] =
new TC[C] { def show(c: C): String = "it's C" }
}

def doit[X](x: X)(implicit tc: TC[X]): Unit = println(tc.show(x))

import TcImplicits._

doit(new A)
doit(new B)
doit(new C)
doit(new D)

现在它在所有情况下都选择最具体的一个:
it's A
it's A
it's C
it's C

解决方法 2:不变的辅助特征

以下是如何通过引入在类型参数中不变的辅助特征来强制交换特定示例中的隐式:
class A
class B extends A

trait TC[-T] { def show(t: T): String }

val showA = new TC[A] { def show(a: A): String = "it's A" }
val showB = new TC[B] { def show(b: B): String = "it's B" }

trait TcImplicit[X] { def get: TC[X] }
implicit val showAImplicit = new TcImplicit[A] { def get = showA }
implicit val showBImplicit = new TcImplicit[B] { def get = showB }

def doit[X](x: X)(implicit tc: TcImplicit[X]): Unit = println(tc.get.show(x))

doit(new A)
doit(new B)

打印
it's A
it's B

关于Scala:将逆变类型作为隐式参数传递不会选择最近的父类(super class)型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52430996/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com