-偉大な名言
そしてこんにちは!
今日は暗黙のScala言語についてお話します。 まだ推測していない人は、暗黙の変換、パラメーター、クラスなどについて話します。XenovExplicitを使用するすべての新規ユーザー、特にPythonの愛好家はImplicitよりも優れています。 1つの記事でコンパイラ全体と原則全体をカバーすることは不可能ですが、道は圧倒されますか?
1.暗黙の変換
そして、暗黙的な変換の比較的単純なセクションから始めます。 そして人生の例。
ヴァシリーは、メーカーのルノーの車を望んでいます。 家族全員が長い間お金を節約していましたが、彼らは全額を貯めることができませんでした。 新しいWHAに十分なお金のみ。 そして、突然拍手! ルノーがAvtoVAZを買収。 製造業者が今必要であり、十分なお金があるようです。 そして、暗黙のうちに、ヴァシャは外国車の幸せな所有者になりました。
次に、これをコードの形式で形式化しようとします。
人生の例
case class Vasiliy(auto: Renault) { println("Vasiliy owns "+auto) } case class Renault(isRussian: Boolean = false) case class VAZ(isRussian: Boolean = true) object VAZ { implicit def vaz2renault(vaz: VAZ): Renault = Renault(vaz.isRussian) // } object Family { def present = { Vasiliy(VAZ()) // . ! } }
Family.present
の実行の結果、
Vasiliy owns Renault(true)
する行が表示され
Vasiliy owns Renault(true)
。 これがScalaがこの困難な生活の中で普通の人々を助ける方法です!
もっとプログラム的な例を挙げれば(私のプロジェクトで似たようなものを使用します):
生気のない例
case class PermissionsList(permissions: Set[String] = Set("UL")); object PermissionsList { implicit def str2permissions(str: String) = PermissionsList(str.split(";").toSet) implicit def permissions2str(p: PermissionsList) = p.permissions.mkString(";") } // case class User(login: String, permissions: PermissionsList) /* somewhere in a galaxy far far away */ User(login = "Vasiliy", permissions = "UL;AL") //
上記のコードにより、文字列を暗黙的にアクセスオブジェクトにキャストしたり、その逆を行うことができます。 これは、同じWeb上で作業するときに便利です。クライアントに
"UL;AL"
という形式の目的の行を
"UL;AL"
付けて、サーバーに送信するだけで、適切なタイミングでオブジェクトに変換されます。
そして、私たちは重要なポイントに来ました 。 VAZ
ほとんどの場合、Scalaのすべての魔法はコンパイル時に発生します(言語は強く型付けされています)。 ローカルコンパイラは非常に賢く、機知に富んだ生き物です。 存在しなかったVAZクラスのインスタンスでexat()メソッドを呼び出そうとするとすぐに、コンパイラーは真剣に起動し
implicit def a2b(a: A): B
彼は暗黙的な変換を探しています:
- 現在のスコープ内(たとえば、現在のオブジェクト内)
- 明示的に(
import app.VAZ.vaz2renault
) - またはグループのインポート(
import app.VAZ._
) - コンパニオンオブジェクトコンバーチブル内
ところで、存在しないメソッドを呼び出すだけでなく、コンパイラは、異なるデータ型のパラメーターを必要とするメソッド/関数にオブジェクトを渡そうとすると、オブジェクトを変換しようとします。 これは、ヴァシリーと彼の家族の例からです。
1.1暗黙のクラス
バージョン2.10から、暗黙クラスがScalaに登場し、既存クラスの拡張機能を簡単にグループ化(メソッドを追加)できるようになりました。 以下に簡単な例を示します。
object MySimpleHelper { implicit class StringExtended(str: String) { def sayIt = println(str) def sayItLouderBitch = println(str.toUpperCase +"!!!") } }
引用された生データからわかるように、単一の引数(文字列)をとるオブジェクト内で宣言されたクラスがあります。 この行は、クラスメソッドの断片に引き裂かれるように与えられています。 そして、このことは単純に苦しめられます。
import MySimpleHelper._ "oh gosh" sayIt > oh gosh "oh gosh" sayItLouderBitch > OH GOSH!!!
ただし、ここで注意しなければならない制限がいくつかあります。
- 暗黙的なクラスの場合、明示的なコンストラクター引数を1つだけ使用できます。実際には「展開」します(暗黙的なパラメーターについては後で説明します)
- そのようなクラスは、オブジェクト、特性、他のクラス内でのみ宣言できます。
- クラス宣言のスコープでは、同じ名前のメソッド、プロパティ、またはオブジェクトは存在できません。 たとえば、オブジェクトに
VAZ
プロパティがある場合、implicit class VAZ
は近くに共存できません
実際、
StringExtended
はコンパイラによって次のように変換されます。
class StringExtended(str: String) { def sayIt = println(str) def sayItLouderBitch = println(str.toUpperCase +"!!!") } implicit def String2StringExtended(str: String): StringExtended = new StringExtended(str)
おなじみですか?
2.暗黙のパラメーター
どういうわけか、すべてが単純すぎて、あなたはすでに退屈していますか? それは少しハードコアの時間です! 脳を動かして岩の根源に登りましょう:
Surlyコード
/** * TraversableOnce.scala: minBy * , , , , , B A . , B , A, B . - . */ def minBy[B](f: A => B)(implicit cmp: Ordering[B]): A = { // - ? if (isEmpty) throw new UnsupportedOperationException("empty.minBy") // var minF: B = null.asInstanceOf[B] var minElem: A = null.asInstanceOf[A] var first = true // // for (elem <- self) { // A, B val fx = f(elem) if (first || cmp.lt(fx, minF)) { // - . // cmp.lt true , f: B < minF: B minElem = elem minF = fx first = false } } minElem }
プッシュされた、それはすべてが明らかであるようだ。
ストップ、2番目。 ただし、次のようなminByを使用します。
val cities = Seq(new City(population = 100000), new City(500000)) val smallCity = cities.minBy( city => city.population )
そして、
cmp: Ordering[B] ( B == Int)
渡しません
cmp: Ordering[B] ( B == Int)
。 コードは機能しているように見えますが...リラックスしてください。 これは魔法です。
インポートされたスコープ、特に
scala.math.Ordering
存在する
そのようなコード
object Ordering extends LowPriorityOrderingImplicits { ... trait IntOrdering extends Ordering[Int] { def compare(x: Int, y: Int) = if (x < y) -1 else if (x == y) 0 else 1 } implicit object Int extends IntOrdering ... }
最後の行に注意しましょう-IntOrdering
IntOrdering
Ordering[Int]
継承するときに実装される
compare
メソッドを含む暗黙のIntオブジェクトがあり
IntOrdering
。 実際、このオブジェクトは比較のために使用され、暗黙的に不運な
minBy
ます。
非常に単純化された例は次のようになります。
フレンドリーコード
implicit val myValue: Int = 5 object Jules { def doesHeLookLikeABitch(answer: String)(implicit times: Int) = { for(x <- 1 to times) println(answer ) } } Jules.doesHeLookLikeABitch("WHAT?") >WHAT? >WHAT? >WHAT? >WHAT? >WHAT?
もちろん、ハンドルによって暗黙的なパラメーターを転送することを禁止する人はいません。 いいえ、まあ、突然必要になります。
そして、繰り返しますが、制限はありません。
- 暗黙的としてマークされたオブジェクト/値は、メソッド呼び出しのスコープ内に存在する必要があり、1つのデータ型に対して1つのパラメーターしか存在できません。 そうしないと、コンパイラはメソッドに渡す必要があるものを理解できません。
- あるいは、コンパイラーは、
implicit T
コンパニオンオブジェクトが存在する場合はそれをimplicit val x: T
を引き出します。 しかし、私にとっては、これらはすでに非常に難しい薬です。
3.ビュー/コンテキストの境界
脳がすでに溶けている場合は、休憩してコーヒーを飲むか、何か強いものを飲んでください。 今日の最新の非自明性についてお話します。
新しい車(
exat()
車)を運転するVasilyが成功した人、つまりプログラマーになったとしましょう。 そして今、VasilyはScalaについて書いており、彼はもう1つのSUGAR ARRHHを望んでいました。 マーティンは考えて言った-わかりました。 そして、それらにタイプと制限を導入しました。 同じ
def f[T](a: T)
3.1ビューの境界
型を宣言するときのこの制限は、コンパイラに
def f[A <% B](a: A) = a.bMethod
つまり アクセス可能なスコープで
A
から
B
への暗黙的な変換があります。 原則として、次の形式のエントリを想像できます。
def f[A](a: A) (implicit a2b: A => B) = a.bMethod:
ロシア人に近い例は次のようになります。
class Car { def exat() = println("POEXALI") } class VAZ object VAZ { implicit def vaz2car(v: VAZ): Car = new Car() } def go[A <% Car](a: A) = a.exat() go(new VAZ()) > POEXALI
いいね! 人生は美しくなり、髪は元に戻り、妻は戻ってきました。
しかし、ヴァシリーはそれを求めました、そして、マーティンはもう止められませんでした...それで、それは現れました
3.2コンテキスト境界
この制限はScala 2.8で導入されたもので、View Boundsとは異なり、暗黙的な変換には責任を負いませんが、暗黙的なパラメーターには責任があります 。
def f[A : B](a: A) = g(a) // g B[A]
最も単純な例は、そのようなペアです。
def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b vs def f[A](a: A, b: A)(implicit ord: Ordering[A]) = { import ord._ if (a < b) a else b }
実際、これはHaskellと彼のタイプクラスパターンの遠いあいさつです。
あとがきの代わりに
道はそれで終わりではありません;長い間Scalaについて話すことができます。 しかし、一度にすべてではありません。なぜなら、主なことは理解と理解への欲求だからです。 欲求には、何が起こっているのかが認識されます。
この記事を読んだ後、暗黙的な変換を使用するプロジェクトのコードを理解できない場合は、メモ帳を閉じて通常のIDEを開くことをお勧めします。 そして、私の頭は沸騰しません、私は行きます。 ご清聴ありがとうございました。