首页 文章

为什么DummyImplicit不会消除[String](a:A)(a:String)的歧义

提问于
浏览
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行:我的目的是传递给工厂“Attr”,为其生成“String”值类型“String”以及名称“foo” .

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

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

阅读了有关type erasure and DummyImplicit的文章并查阅Scala参考部分"7.2 Implicit parameters" I thought "(implicit dummy: DummyImplicit)" would do the trick 之后 .

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

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)
}

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

相关问题