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」に値型「文字列」と、それが生成するすべての属性の名前「foo」を渡すことです。

行 2: 以前に構成された属性ファクトリを使用して、実際には「String」型の値「bar」を持つ「foo」という名前の属性を作成しています。

私の結論: このファクトリ オブジェクトのパラメーター化された型 "A" は "String" であるため、Scala コンパイラーはメソッド "apply" の同じパラメーター シグネチャが "(value: String)" であると推測しますが、これはあいまいです。したがって、暗黙のパラメーター リストを追加することで、署名に違いを作ろうとしました。

型消去と DummyImplicitに関する記事を読み、Scala のリファレンス セクション「7.2 Implicit parameters」を参照した後、「(implicit dummy: DummyImplicit)」でうまくいくと思いました

今のところ、私の解決策は最小限のラッパーを持つことです:

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

「Str To Txt」型の暗黙の値、つまり適切な変換関数が見つかった場合、上記の 2 行目がコンパイルされます。つまり、次のようになります。

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な型の任意の値を取ります(その場合、暗黙的な変換が使用されます)。BA == StringPredef.conforms

于 2011-08-23T03:57:10.007 に答える