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

網羅的マッチング

コンパイラーが網羅性を検査します。

レッスン 4/413 ステップ

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

網羅的マッチングとは

マッチング対象の型が取り得るすべての値を処理するとき、そのmatchは網羅的です。

sealed traitでは、コンパイラーがすべてのバリアントを把握しているため、matchがすべてを網羅しているか確認できます。

完全なMatch

sealed traitのすべてのバリアントを処理すると、コンパイラーは問題ないと判断し、警告は表示されません。

sealed trait Color
case object Red extends Color
case object Green extends Color
case object Blue extends Color
object Main {
  def name(c: Color): String = c match {
    case Red   => "red"
    case Green => "green"
    case Blue  => "blue"
  }
  def main(args: Array[String]): Unit = {
    println(name(Blue))
  }
}

コンパイラーが安全を守る

バリアントを1つでも省略すると、コンパイラーはコンパイル時に非網羅的なmatchの警告を出します。

これは安全網として機能し、プログラムを実行する前に不足に気付けます。

後からバリアントを追加する

新しいバリアントを追加したときに、本当の効果が現れます。コードベース全体にある非網羅的なmatchがすべて警告になり、新しいケースを処理するよう促されます。

これにより、リファクタリングを安全かつ予測可能に行えます。

ワイルドカードを避ける理由

case _ =>を追加すると、網羅性に関する警告を抑制できます。しかし、後からバリアントを追加したときにバグを隠す可能性があります。

sealed ADTでは、コンパイラーの保護を維持できるよう、各バリアントを明示的に列挙することをおすすめします。

sealed trait Status
case object Active extends Status
case object Inactive extends Status
object Main {
  def label(s: Status): String = s match {
    case Active   => "on"
    case Inactive => "off"
  }
  def main(args: Array[String]): Unit = {
    println(label(Active))
  }
}

データを持つ場合の網羅性

網羅性は、データを持つバリアントにも適用されます。フィールドを束縛したうえで、すべてのバリアントを引き続き処理する必要があります。

sealed trait Shape
case class Circle(r: Double) extends Shape
case class Square(s: Double) extends Shape
object Main {
  def area(sh: Shape): Double = sh match {
    case Circle(r) => 3.14159 * r * r
    case Square(s) => s * s
  }
  def main(args: Array[String]): Unit = {
    println(area(Circle(2)))
    println(area(Square(3)))
  }
}

ガードとの組み合わせ

注意が必要です。コンパイラーはガードがすべての値を網羅していることを証明できないため、ガードによってmatchが非網羅的になることがあります。

網羅性を維持するには、同じバリアントに対するガードなしの最後のケースを用意してください。

sealed trait Temp
case class Celsius(v: Int) extends Temp
object Main {
  def feel(t: Temp): String = t match {
    case Celsius(v) if v >= 30 => "hot"
    case Celsius(v)            => "not hot"
  }
  def main(args: Array[String]): Unit = {
    println(feel(Celsius(35)))
    println(feel(Celsius(10)))
  }
}

Optionの網羅性

標準ライブラリのOptionは、SomeとNoneを持つsealed ADTです。両方にマッチすれば網羅的になります。

object Main {
  def show(o: Option[Int]): String = o match {
    case Some(v) => s"value $v"
    case None    => "nothing"
  }
  def main(args: Array[String]): Unit = {
    println(show(Some(7)))
    println(show(None))
  }
}

ネストした場合の網羅性

網羅性は、ネストしたADTにも役立ちます。コンパイラーは、分解する各レベルについて推論します。

sealed trait Tree
case object Leaf extends Tree
case class Node(v: Int, l: Tree, r: Tree) extends Tree
object Main {
  def depth(t: Tree): Int = t match {
    case Leaf          => 0
    case Node(_, l, r) => 1 + math.max(depth(l), depth(r))
  }
  def main(args: Array[String]): Unit = {
    println(depth(Node(1, Leaf, Node(2, Leaf, Leaf))))
  }
}

重要な理由

コンパイラーがチェックする網羅性には、次の利点があります。

  • すべてのケースが処理されているという確信を得られます
  • ADTが拡張されたときに自動的に通知されます
  • 実行時のMatchErrorを減らせます
  • 大規模なリファクタリングをより安全に行えます

すべてを組み合わせる

すべてのケースを網羅するsealed ADTです。ここに新しいバリアントを追加すると、コンパイラーの警告が発生します。

sealed trait Command
case object Start extends Command
case object Stop extends Command
case class SetSpeed(v: Int) extends Command
object Main {
  def run(c: Command): String = c match {
    case Start       => "starting"
    case Stop        => "stopping"
    case SetSpeed(v) => s"speed $v"
  }
  def main(args: Array[String]): Unit = {
    List(Start, SetSpeed(5), Stop).foreach(c => println(run(c)))
  }
}

クイックチェック

網羅的マッチングについての理解度を確認しましょう。

まとめ

網羅的マッチングについて学びました。

  • すべてのバリアントを網羅すると、matchは網羅的です
  • sealed traitではコンパイラーがこれを確認し、不足があると警告します
  • バリアントを追加すると、不完全なmatchがすべて明らかになります
  • この保護を維持するため、sealed ADTではcase _を避けます
  • ガードによって網羅性が失われることがあるため、ガードなしのフォールバックを追加します
無料で開始

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は初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「網羅的マッチング」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ケースクラス
  2. Sealed トレイト
  3. 代数的データ型
  4. 網羅的マッチング
← Scala for Backend Engineering & Functional Programmingに戻る