1

给定以下代码:

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)”,这是模棱两可的。因此,我尝试通过添加隐式参数列表来改变签名。

在阅读了一篇关于类型擦除和 DummyImplicit的文章并查阅了 Scala 参考部分“7.2 隐式参数”后,我认为“(隐式假人:DummyImplicit)”可以解决问题

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

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

假设可以找到“Str To Txt”类型的隐式值,即合适的转换函数,则上面的第二行编译,即:

2| val catch22 = FooAttr("bar")

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

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

1 回答 1

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将采用任何B可转换为的类型值A == String,包括字符串本身(Predef.conforms在这种情况下使用隐式转换)。

于 2011-08-23T03:57:10.007 回答