私はScalaのplayframeworkチュートリアルをやり遂げていました、そして私が戸惑っていたこのコードの断片に出会いました:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
それで私は調査して遭遇しました この記事 。
まだわかりません。
これはどう違いますか?
implicit def double2Int(d : Double) : Int = d.toInt
そして
def double2IntNonImplicit(d : Double) : Int = d.toInt
明らかな事実を除いて、それらは異なるメソッド名を持っています。
implicit
はいつ使用すべきですか。
以下に暗黙の主な使用例を説明しますが、詳細については Scalaでのプログラミングの関連章 を参照してください。
暗黙のパラメータ
メソッドの最後のパラメータリストにはimplicit
name__というマークを付けることができます。これは、値が呼び出されたコンテキストから値が取得されることを意味します。スコープ内に正しい型の暗黙の値がない場合はコンパイルされません。暗黙的な値は単一の値に解決され、衝突を回避する必要があるので、型をその目的に固有のものにすることをお勧めします。あなたのメソッドが暗黙のInt
name__を見つけることを要求しないでください!
例:
// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s
// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc") // returns "***abc"
暗黙の変換
コンパイラがコンテキストに対して間違った型の式を見つけると、型チェックを許可する型の暗黙のFunction
name__値を探します。そのため、A
name__が必要であり、B
name__が見つかった場合は、スコープ内でB => A
型の暗黙的な値を探します(存在する場合は、B
name__およびA
name__コンパニオンオブジェクトなど、他の場所もチェックします)。 def
name__sはFunction
name__オブジェクトに "eta-expansion"できるので、implicit def xyz(arg: B): A
も同様にできます。
したがって、implicit
name__が見つかったがDouble
name__が必要な場合は、Int
name__とマークされたものがコンパイラーによって自動的に挿入されるという点が、メソッドの違いです。
implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0
と同じように動作します
def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)
2番目の例では、変換を手動で挿入しました。最初は、コンパイラは同じことを自動的に行いました。左側に型注釈があるため、変換が必要です。
Playからの最初のスニペットについて:
アクションはPlayドキュメントの このページ で説明されています( API docs もご覧ください)。あなたが使っている
apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]
Action
name__オブジェクト(これは同名の特性の仲間です)。
そのため、引数として関数を指定する必要があります。これはリテラルとして次の形式で書くことができます。
request => ...
関数リテラルでは、=>
の前の部分は値宣言です。他のimplicit
name__宣言と同様に、必要に応じてval
name__とマークできます。ここで、request
name__NOTにチェックをタイプするにはimplicit
name__とマークする必要がありますが、そうすることで暗黙的な値として利用可能になりますそれは関数内でそれを必要とするかもしれません(そしてもちろん、それは明示的にも使用することができます)。この特定のケースでは、 Form クラスのbindFromRequest
name__メソッドが暗黙のRequest
name__引数を必要とするため、これが行われました。
警告:は慎重に皮肉を含みます! YMMV ...
Luigi's answer 完全で正しいです。これはScalaプロジェクトで頻繁に起こるので、あなたがどうやって見事に使い過ぎることができるかの例でそれを少しだけ拡張することです意味。実際、それほど頻繁には、"ベストプラクティス"ガイドのうちの1つでも見つけることができるでしょう。
object HelloWorld {
case class Text(content: String)
case class Prefix(text: String)
implicit def String2Text(content: String)(implicit prefix: Prefix) = {
Text(prefix.text + " " + content)
}
def printText(text: Text): Unit = {
println(text.content)
}
def main(args: Array[String]): Unit = {
printText("World!")
}
// Best to hide this line somewhere below a pile of completely unrelated code.
// Better yet, import its package from another distant place.
implicit val prefixLOL = Prefix("Hello")
}
request
パラメーターをimplicit
としてマークする理由とタイミング
アクションの本体で使用するメソッドの中には、暗黙のパラメータリストを持つものがあります。たとえば、Form.scalaはメソッドを定義します。
def bindFromRequest()(implicit request: play.api.mvc.Request[_]): Form[T] = { ... }
myForm.bindFromRequest()
を呼び出すだけでよいので、必ずしもこれに気付く必要はありません。暗黙の引数を明示的に指定する必要はありません。いいえ、リクエストのインスタンスを必要とするメソッド呼び出しに遭遇するたびに渡される有効な候補オブジェクトを探すためにコンパイラのままにします。あなたはdoリクエストが利用可能なので、あなたがする必要があるのはそれをimplicit
としてマークすることだけです。
あなたは明示的に利用可能としてそれを暗黙的使用のために印を付けます。
Playフレームワークによって送信されたリクエストオブジェクトを使用することは「OK」であることをコンパイラに示唆します(「request」という名前を付けましたが、「r」または「req」だけを使用することもできます)。 。
myForm.bindFromRequest()
それを見ますか?それはありませんが、それはisあります!
必要なすべての場所に手動でスロットを挿入する必要はありません(ただし、implicit
とマークされているかどうかにかかわらず、can明示的に渡すことができます)。
myForm.bindFromRequest()(request)
それを暗黙のうちにマークしないで、あなたはしなければならないでしょう。暗黙のうちにそれをマーキングする必要はありません。
の場合、リクエストにimplicit
のマークを付けますか?あなたが本当に必要とするのは、Requestのインスタンスを期待する暗黙のパラメータリストを宣言するメソッドを利用する場合だけです。しかし、それを簡単にするために、要求をimplicit
always とマークする習慣をつけることができます。そうすれば、美しい簡潔なコードを書くことができます。
また、上記の場合、型がonly one
であるdouble => Int
暗黙関数があるはずです。そうでなければ、コンパイラは混乱し、正しくコンパイルされません。
//this won't compile
implicit def doubleToInt(d: Double) = d.toInt
implicit def doubleToIntSecond(d: Double) = d.toInt
val x: Int = 42.0
scalaで暗黙的に機能する:
コンバーター
パラメータ値インジェクタ
暗黙の使用には3つのタイプがあります
暗黙的な型変換:割り当てを生成するエラーを意図した型に変換します
val x:String = "1"
val y:Int = x
StringはIntのサブタイプではないため、2行目でエラーが発生します。エラーを解決するために、コンパイラは暗黙的なキーワードと引数としてStringを取り、Intを返します。
そう
implicit def z(a:String):Int = 2
val x :String = "1"
val y:Int = x // compiler will use z here like val y:Int=z(x)
println(y) // result 2 & no error!
暗黙的にレシーバー変換:通常、レシーバーによってオブジェクトのプロパティを呼び出します。メソッドまたは変数。そのため、レシーバーによってプロパティを呼び出すには、プロパティがそのレシーバーのクラス/オブジェクトのメンバーである必要があります。
class Mahadi{
val haveCar:String ="BMW"
}
class Johnny{
val haveTv:String = "Sony"
}
val mahadi = new Mahadi
mahadi.haveTv // Error happening
ここでmahadi.haveTvはエラーを生成します。 scalaコンパイラは、最初にhaveTvプロパティをmahadi受信者に検索するためです。見つかりません。次に、引数としてMahadiオブジェクトを取り、Johnnyオブジェクトを返す暗黙キーワードを持つスコープ内のメソッドを探します。しかし、ここにはありません。 errorを作成します。しかし、次は大丈夫です。
class Mahadi{
val haveCar:String ="BMW"
}
class Johnny{
val haveTv:String = "Sony"
}
val mahadi = new Mahadi
implicit def z(a:Mahadi):Johnny = new Johnny
mahadi.haveTv // compiler will use z here like new Johnny().haveTv
println(mahadi.haveTv)// result Sony & no error
暗黙的にパラメーターを挿入:メソッドを呼び出してパラメーター値を渡さないと、エラーが発生します。 scalaコンパイラーはこのように動作します-最初に値を渡そうとしますが、パラメーターの直接値を取得しません。
def x(a:Int)= a
x // ERROR happening
次に、パラメーターに暗黙的なキーワードがある場合、スコープで同じタイプの値を持つvalを探します。取得しない場合、エラーが発生します。
def x(implicit a:Int)= a
x // error happening here
この問題を解決するために、コンパイラはimplicit valを探します-type of Intパラメータaにはimplicitキーワードがあるため=。
def x(implicit a:Int)=a
implicit val z:Int =10
x // compiler will use implicit like this x(z)
println(x) // will result 10 & no error.
別の例:
def l(implicit b:Int)
def x(implicit a:Int)= l(a)
次のように書くこともできます
def x(implicit a:Int)= l
lには暗黙のパラメーターがあり、メソッドxの本体のスコープ内にあるため、暗黙のローカル変数(パラメータはローカル変数です)aこれはxのパラメータなので、xの本体メソッドメソッドの署名lの暗黙の引数値はxメソッドのローカルの暗黙の変数(パラメーター)a
暗黙的に。
そう
def x(implicit a:Int)= l
このようなコンパイラになります
def x(implicit a:Int)= l(a)
別の例:
def c(implicit k:Int):String = k.toString
def x(a:Int => String):String =a
x{
x => c
}
c in x {x => c}引数または暗黙のval スコープ内で明示的に値を渡す必要があるため、エラーが発生します。
したがって、method xを呼び出すときに、関数リテラルのparameterを明示的に作成できますimplicit
x{
implicit x => c // the compiler will set the parameter of c like this c(x)
}
これは、Play-Frameworkのaction methodで使用されています
def index = Action{
implicit request =>
Ok(views.html.formpage)
}