gpt4 book ai didi

scala - 类型成员的上下文边界或如何将隐式解析推迟到成员实例化

转载 作者:行者123 更新时间:2023-12-04 21:11:27 27 4
gpt4 key购买 nike

在以下示例中,有没有办法避免隐式解析选择 defaultInstance并使用 intInstance反而?代码后的更多背景:

// the following part is an external fixed API

trait TypeCls[A] {
def foo: String
}

object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo

implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}

implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}

trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}

// end of external fixed API

class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}

class MyFooP extends FooP[Int]

class MyFooM extends FooM { type A = Int }

object Main extends App {

println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}

实际输出:
With type parameter: integer
With type member: default

期望的输出:
With type parameter: integer
With type member: integer

我正在使用使用上述方案为类型类 TypeCls 提供“默认”实例的第三方库。 .我认为上面的代码是一个演示我的问题的最小示例。

用户应该混入 FooM特征并实例化抽象类型成员 A .问题是由于 defaultInstance (new MyFooM).foo的电话不解决专门的 intInstance而是提交给 defaultInstance这不是我想要的。

我添加了一个使用类型参数的替代版本,称为 FooP (P = 参数,M = 成员)避免解析 defaultInstance通过使用绑定(bind)在类型参数上的上下文。

有没有等效的方法来使用类型成员?

编辑:我的简化有一个错误,实际上是 foo不是 def但是一个 val ,因此无法添加隐式参数。因此,当前的答案均不适用。
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}

// end of external fixed API

class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}

最佳答案

在这种特定情况下,最简单的解决方案是使用 foo本身需要 TypeCls[A] 的隐式实例.
唯一的缺点是它会在每次调用 foo 时被传递。而不是仅在实例化时FooM .因此,您必须确保它们在每次调用 foo 时都在范围内。 .虽然只要 TypeCls实例在伴随对象中,你不会有什么特别的事情要做。

trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}

更新 :在我上面的回答中,我设法错过了 FooM 的事实。无法修改。此外,该问题的最新编辑提到 FooM.foo实际上是一个 val而不是 def .

坏消息是您使用的 API 完全损坏了。没办法 FooM.foo将永远返回任何有用的东西(无论 TypeCls[A] 的实际值如何,它总是将 TypeCls.defaultInstance 解析为 A )。唯一的出路是覆盖 foo在派生类中, A 的实际值是已知的,以便能够使用 TypeCls 的正确实例.幸运的是,这个想法可以与您使用具有上下文绑定(bind)的类的原始解决方法相结合(在您的情况下为 FooP):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}

现在不要让你的类扩展 FooM直接让他们扩展 FooMEx :
class MyFoo extends FooMEx[Int]
FooMEx 之间的唯一区别和你原来的 FooP类是 FooMEx 延长 FooM , 所以 MyFooFooM 的正确实例因此可以与固定的 API 一起使用。

关于scala - 类型成员的上下文边界或如何将隐式解析推迟到成员实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33782119/

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