24

暗黙のパラメーターを取るいくつかのメソッドでクラスを定義しようとしています:

object Greetings {
  def say(name: String)(implicit greetings: String): String = greetings + " " +name 
}

このクラスを別のクラスから使用します

implicit val greetings = "hello"                //> greetings  : java.lang.String = hello
Greetings.say("loic")                           //> res0: String = hello loic
Greetings.say("loic")("hi")                     //> res1: String = hi loic

私の問題は、Greetings オブジェクトの外部で暗黙の val を定義した場合にのみ機能することです。API (Scala コレクション API など) を簡単に使用できるように、メソッドに暗黙的なパラメーターとクラス内のデフォルト値を提供できるようにしたいと考えています。

だから私はこれをしたいのですが、うまくいきません(暗黙の値が見つかりません):

object Greetings {
  implicit val greetings = "hello"    
  def say(name: String)(implicit greetings: String): String = greetings + " " +name 
}

その後

Greetings.say("loic")                         
Greetings.say("loic")("hi") 

デフォルト値を定義できることはわかっています(implicit greetings: String = "hello")が、メソッドが多数ある場合の繰り返しを避けるために、クラスレベルで定義したいと考えています。

たとえばCanBuildFrom、クラス内で定義されているのを見たので、何かが足りないと思います。List

4

2 に答える 2

26

String暗黙のように一般的な型を使用するのは悪い考えです。主な理由は、暗黙的なルックアップが型のみに基づいているためです。他の誰かが String 型の別の暗黙的な値を定義した場合はどうなるでしょうか? 衝突してしまうかもしれません。したがって、独自の目的のために独自の特定のタイプを定義する必要があります (String の単純なラッパー)。

もう 1 つの理由は、暗黙的な値を探すときに、コンパイラは (他の場所の中でも) 暗黙的な値の型のコンパニオン オブジェクト (存在する場合) を調べるためです。コンパニオンオブジェクトはデフォルトの暗黙的な値を配置する自然な場所であるため(あなたの場合のように)、それがどれほど便利であるかを簡単に確認できます。ただし、暗黙的な値が所有していない型 ( などString) である場合は、そのためのコンパニオン オブジェクトを作成することはできませんが、独自のラッパー型では問題はありません。

OK、言い回しは十分です。これを行う方法は次のとおりです。

case class Greetings( value: String ) {
  override def toString = value
}
object Greetings {
  // this implicit is just so that we don't have to manually wrap 
  // the string when explicitly passing a Greetings instance
  implicit def stringToGreetings( value: String ) = Greetings( value ) 

  // default implicit Greetings value
  implicit val greetings: Greetings ="hello"

  def say(name: String)(implicit greetings: Greetings): String = greetings + " " +name 
}
Greetings.say("loic")                         
Greetings.say("loic")("hi") 
于 2012-10-07T12:11:56.767 に答える
12

回避策を見つけました:

class Greetings(implicit val greetings: String = "hello") {
    def say(name: String): String = greetings + " " + name 
}

このように、デフォルト値を設定して、必要に応じてオーバーライドできます。

new Greetings().say("loic")                     //> res0: String = hello loic

implicit val greetings = "hi"                   //> greetings  : java.lang.String = hi
new Greetings().say("loic")                     //> res1: String = hi loic

new Greetings()("coucou").say("loic")           //> res2: String = coucou loic

注:ここで説明されている構文の奇妙さのため、new Greetings()("coucou")は機能していません。new Greetings("coucou")

于 2012-10-07T08:57:31.077 に答える