Scala for Backend Engineering & Functional Programming · レッスン

インスタンスの定義

暗黙のインスタンスです。

レッスン 2/413 ステップ

「インスタンスの定義」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

インスタンスの定義

インスタンスは、特定の型に対して型クラスがどのように振る舞うかをコンパイラーに伝えます。Scalaでは通常、インスタンスにimplicit(Scala 2)を付けるか、given(Scala 3)で宣言し、自動的に見つけられるようにします。

implicit valインスタンス

単純な型クラスなら、implicit valだけで十分です。関数がShow[Int]を必要とすると、コンパイラーがそれを見つけます。

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"Int=$a"

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(123))
  }
}

implicitly:インスタンスを召喚する

implicitly[Show[Int]]は、スコープ内にあるインスタンスをコンパイラーに取得させます。インスタンスの存在をテストしたり、直接アクセスしたりする場合に便利です。

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"<$a>"

  def main(args: Array[String]): Unit = {
    val s = implicitly[Show[Int]]
    println(s.show(8))
  }
}

カスタム型のインスタンス

独自のcase classに対するインスタンスを定義します。データクラスはきれいなまま保ち、フォーマット処理はインスタンスに置きます。

trait Show[A] { def show(a: A): String }

case class Point(x: Int, y: Int)

object Main {
  implicit val pointShow: Show[Point] = (p: Point) => s"(${p.x}, ${p.y})"

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(Point(3, 4)))
  }
}

ジェネリックインスタンスのimplicit def

あるインスタンスが別のインスタンスに依存する場合は、implicit defを使用します。ここではShow[A]からShow[List[A]]を構築します。

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => a.toString

  implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
    (xs: List[A]) => xs.map(s.show).mkString("[", ", ", "]")

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(List(1, 2, 3)))
  }
}

コンパニオンオブジェクト内のインスタンス

型クラスのコンパニオンオブジェクトにインスタンスを置くと、importなしで自動的に見つけられます。デフォルトインスタンスの配置場所として推奨されます。

trait Show[A] { def show(a: A): String }

object Show {
  implicit val intShow: Show[Int] = (a: Int) => s"i:$a"
  implicit val strShow: Show[String] = (a: String) => s"s:$a"
}

object Main {
  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(5))
    println(display("hi"))
  }
}

暗黙スコープと優先順位

コンパイラーはいくつかの場所からインスタンスを検索します。まずローカルスコープとimportされたスコープを検索し、次に関係する型のコンパニオンオブジェクトを検索します。同じ具体性のインスタンスが2つあると、ambiguous implicitエラーになります。

コンテキスト境界の省略記法

def f[A: Show](a: A)という構文はcontext boundです。これは、スコープ内に暗黙のShow[A]が存在しなければならないことを意味します。内部ではimplicitlyで取得します。

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"n=$a"

  def display[A: Show](a: A): String = implicitly[Show[A]].show(a)

  def main(args: Array[String]): Unit = {
    println(display(77))
  }
}

召喚ヘルパー

ライブラリでは、便利なsummonerとしてコンパニオンにapplyメソッドを追加します。Show[Int]でインスタンスを返せます。implicitlyよりもすっきり書けます。

trait Show[A] { def show(a: A): String }

object Show {
  def apply[A](implicit s: Show[A]): Show[A] = s
  implicit val intShow: Show[Int] = (a: Int) => s"=$a"
}

object Main {
  def main(args: Array[String]): Unit = {
    println(Show[Int].show(10))
  }
}

孤児インスタンスを避ける

孤児インスタンスとは、型クラスとも型とも一緒に定義されていないインスタンスです。合法ではありますが、importによって動作が一貫しなくなる可能性があります。一貫性を保つため、コンパニオンオブジェクトのインスタンスを優先してください。

まとめて確認する

コンパニオンオブジェクトのインスタンス、派生したリストインスタンス、召喚ヘルパーを含む完全なプログラムです。

trait Show[A] { def show(a: A): String }

object Show {
  def apply[A](implicit s: Show[A]): Show[A] = s
  implicit val intShow: Show[Int] = _.toString
  implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
    (xs: List[A]) => xs.map(s.show).mkString(", ")
}

object Main {
  def main(args: Array[String]): Unit = {
    println(Show[List[Int]].show(List(4, 5, 6)))
  }
}

理解度チェック

インスタンスの定義に関する知識を確認しましょう。

まとめ

インスタンスの定義について学びました。

  • 単純なインスタンスにはimplicit val、派生インスタンスにはimplicit defを使用します。
  • implicitlyまたはコンパニオンのapplyで召喚します。
  • [A: Show]のようなcontext boundを省略記法として使用します。
  • 孤児インスタンスを避けるため、インスタンスはコンパニオンオブジェクトに置きます。
無料で開始

AI チューターと学ぶ Scala — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
39
レッスン
143

よくある質問

「インスタンスの定義」レッスンは無料ですか?

はい。「インスタンスの定義」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「インスタンスの定義」で何を学びますか?

暗黙のインスタンスです。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「インスタンスの定義」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 型クラスパターン
  2. インスタンスの定義
  3. よく使う型クラス
  4. 型クラスの導出
← Scala for Backend Engineering & Functional Programmingに戻る