【问题标题】:Why does DummyImplicit not disambiguate [String](a: A) from (a: String)为什么 DummyImplicit 不能消除 [String](a: A) 与 (a: String) 的歧义
【发布时间】:2011-08-22 20:50:32
【问题描述】:

给定以下代码:

final case class Attr[A](name: String)(implicit conv: String To A) {
  def apply(value: A)(implicit dummy: DummyImplicit) = Attribute(name, value)
  def apply(value: String) = Attribute[A](name, value)
}

Scala 编译器在看到后面的值时会抱怨“对重载定义的模糊引用”:

1| val FooAttr = Attr[String]("foo")
2| val catch22 = FooAttr("bar")

第 1 行:我的意图是将值类型“String”以及它所产生的所有属性的名称“foo”传递给产生“Attributes”的工厂“Attr”。

第 2 行:使用之前配置的属性工厂,我实际上正在生成一个名为“foo”的属性,其值为“bar”,类型为“String”。

我的结论:因为这个工厂对象的参数化类型“A”是“String”,所以 Scala 编译器推断方法“apply”的相同参数签名是“(value:String)”,这是不明确的。因此,我尝试通过添加隐式参数列表来改变签名。

在阅读了一篇关于 type erasure and DummyImplicit 的文章并查阅了 Scala 参考部分“7.2 隐式参数”我认为“(implicit dummy: DummyImplicit)”可以解决问题

目前我的解决方案是使用最小的包装器:

final case class Txt(str: String) {
  override def toString = str
}

鉴于可以找到类型为“Str To Txt”的隐式值,即合适的转换函数,因此编译上面的第二行,即:

2| val catch22 = FooAttr("bar")

看来我想得太复杂了。而不是用(value: String) 的参数列表重载apply 方法,我只是摆脱了它。完全符合我期望的版本现在看起来像:

final case class Attr[A](name: String)(implicit conv: String To A) {
  def apply(value: A) = Attribute(name, value)
}

【问题讨论】:

  • 您能否发布一个简化的、独立的代码示例来显示您收到的错误消息?我不太明白你的意图。
  • 另外:在您链接的 Stack Overflow 问题的答案中,retronym 指出:请将此视为学习擦除、上下文边界和隐式搜索的机会,而不是作为应用在实际代码中!也许有更简单的方法来实现你所需要的。
  • 我更新了这篇文章,让我的意图和结论更加清晰。

标签: scala type-erasure implicits


【解决方案1】:

这个怎么样?

case class Attribute[A](name: String, value: A)

case class AttrBuilder[A](name: String)(implicit conv: String => A) {
  def apply[B](value: B)(implicit conv: B => A) = Attribute(name, conv(value))
}

val bldr = new AttrBuilder[String]("MyAttrs")

bldr("hello") // Attribute(MyAttrs, hello)

implicit def int2string(x: Int) = x.toString
bldr(2)       // Attribute(MyAttrs, 2), using int2string implicit

bldr(false)   // fails; cannot find implicit Boolean => String

属性构建器bldr 将采用可转换为A == StringB 类型的任何值,包括字符串本身(在这种情况下使用隐式转换Predef.conforms)。

【讨论】:

  • 首先非常感谢您的回复。尽管我希望在原始帖子中看到我的示例代码,但我最感兴趣的是一个问题,为什么 Scala 编译器在找到第二个隐式参数列表并且找到 DummyImplicit 类型的值时不会产生影响在预定义中。
  • 现在,关于您的提议:不幸的是,AttrBuilder 过于笼统。通过使用String 类型对其进行参数化,其apply 方法应该接受源类型String 的值,将给定值转换为目标类型A,或者立即接受目标类型A 的值。
  • 我找到了满足我需求的解决方案。见我原帖的结尾。
猜你喜欢
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
相关资源
最近更新 更多