1

String高階関数を適用できる新しい apply メソッドで拡張しようとしています。例:

case class A(s:String, f: List[String] => List[String])

val f: List[String] => List[String] = { ... stuff ... }
"foo"{f} // == A("foo", f)

そのため、関数を受け取る apply メソッドを使用して、文字列から何かへの暗黙的な変換を定義しましたList[String] => List[String]

implicit def c(s:String) = new {
    def apply(f: List[String] => List[String]) = A(s, f)
}

しかし、私がそれを使用しようとすると、変換は Predef に変換Stringされるものと衝突しStringOpsます。

scala> "foo"{f}                                                
<console>:19: error: type mismatch;
 found   : java.lang.String
 required: ?{val apply: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method c in object $iw of type (s: String)java.lang.Object{def apply(f: (List[String]) => List[String]): A}
 and method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
 are possible conversion functions from java.lang.String to ?{val apply: ?}
       "foo"{f}
   ^

required: ?{val apply: ?}私のタイプの引数を取るメソッド ( ) ではなく、一般的な適用メソッド ( ) を探すのはなぜList[String] => List[String]ですか?

編集:

変数を表現するために裸の文字列を使用しないようにすることでこれを解決しました(プロジェクトではgithubで作業しています)。したがって、次のようになります。

case class param(val v: String) {
    def apply(f: Emit.Selector) = Variable(v, f)
}

val $foo = param("foo")
foo{selector} // works fine

そして、暗黙を使用する必要はありません。

さらにアップデート

scala は、検索時に暗黙の結果の型で型パラメーターを検索するようです。私はこれを機能させますが、関数パラメーターと適用メソッドを使用したシナリオは機能しません。どうして?

scala> class A()
defined class A

scala> class B()
defined class B

scala> implicit def one(s:String) = new {
     |   def a(a:A) = s + " A"
     | }
one: (s: String)java.lang.Object{def a(a: A): java.lang.String}

scala> implicit def another(s:String) = new {
     |   def a(b:B) = s + " B"
     | }
another: (s: String)java.lang.Object{def a(b: B): java.lang.String}

scala> "hello" a new A
res1: java.lang.String = hello A

scala> "hello" a new B
res2: java.lang.String = hello B
4

3 に答える 3

2

これを書くとき:

"foo"{f}

コンパイラはそれを次のように変換します。

"foo".apply { f }

より一般的に:applyupdateは、コンパイラに存在するシンタックス シュガーの 2 つの特別なメソッドです。

obj(arg)         // gets translated to:  obj.apply(arg)
obj(index) = arg // gets translated to:  obj.update(index, arg)

StringOps は既に を提供しておりapply(index: Int)、暗黙的な変換を探している間、コンパイラはapply(パラメーターに関係なく) というメンバーを最終的に提供する最初のものを探します。あなたの場合、競合があります。

たぶん、メソッドの名前を次のようなものに変更できます

"foo" useFor { f }

ところで、暗黙的な変換の戻り値の型を常に宣言することをお勧めします。new { def apply /* ... */ }さらに、その後の呼び出しはapplyJava リフレクションを介して行われるため、効率が低下するため、パフォーマンスが重要な状況ではこのスタイルを避ける必要があります。

于 2011-05-06T08:24:46.713 に答える
1

scalacに渡すことで、すべての標準インポート (したがって、すべての標準暗黙) を「無効」にすることができます-Yno-imports(repl では機能しません)。これにより競合は回避されますが、使用するすべてのものを明示的にインポートする必要があります。

于 2011-05-06T09:35:23.693 に答える
1

c からaugmentStringへの変換を変更してシャドウすることもできますが、優先度の低い別の変換(wrapString)が邪魔になることがわかります。ただし、augmentString をシャドウし、これを LowPriorityImplicits の拡張に追加すると、次のようになります。

object HighPriorityImplicits extends LowPriorityImplicits {
  implicit def augmentString(s:String) = new { 
    def apply(f: List[String] => List[String]) = A(s, f) 
  }
}

次に、動作するはずです:

import HighPriorityImplicits._
"foo"{f}

参照:デフォルトで使用される暗黙の変換を制御する方法はありますか?

于 2011-05-06T12:08:43.083 に答える