【Scale】パターンマッチングとサンプルクラス

10618 ワード

パターンマッチング
パターンマッチング(pattern-matching)を理解するには、まずこの2つの単語を分解し、パターン(pattern)とは何かを理解し、ここでのパターンはデータ構造上であり、このパターンは構造の構成を記述するために使用される.
「正規表現」のパターンを連想しやすいです.いいですね.このpatternは正規表現のpatternと似ていますが、適用範囲はもっと広く、さまざまなタイプのデータ構造に対して、正規表現ではなく文字列に対してのみ使用できます.例えば、正規表現の「^A.*」というpatternは、Aの先頭、後続の1つ以上の文字からなる文字列を表す.List(「A」,,*)もpatternであり、最初の要素が「A」であり、後続の1つ以上の要素のListであることを示す.
match式の違い
match式はJavaスタイルswitchの汎化と見なすことができる.各モードが定数であり、最後のモードが共通である場合、Javaスタイルのswitchは自然にmatch式として表現することができる.しかし、3つの違いを覚えておく必要があります.
1. match           ,  Scala      
2. Scala                     。 C    C   ,           break     switch。
3.         ,MatchError      。                    ,                       

パターンの種類
1、スルーモード()任意のオブジェクトを一致させ、デフォルトの「全一致(catch-all)」の予備オプション2として使用され、定数モデルは自身のみを一致させ、任意の字面量は定数3として使用でき、変数モードはワイルドカードモードと類似しており、任意のオブジェクトを一致させることができる.ワイルドカード()違いは、Scalaが変数を一致するオブジェクトにバインドすることです.
//  ,  expr  
//somethingElse       expr,    expr  
expr match {
    case 0 => "zero"
    case somethingElse => "not zero: " + somethingElse
}

4、コンストラクタモードは深さマッチング(deep match)を提供し、準備オプションがサンプルクラスである場合、コンストラクタモードはまずオブジェクトがその準備オプションのサンプルクラスインスタンスであるかどうかを検査し、次にオブジェクトのコンストラクタパラメータが追加の提供モードに合致しているかどうかを検査する.コンストラクタモードでは、最上位オブジェクトが一致しているかどうかだけでなく、オブジェクトの内容が内層のモードに一致しているかどうかもチェックされます.追加のモード自体がコンストラクタモードを形成できるため、オブジェクト内部の任意の深さをチェックすることができます.
//        ,             
abstract class Item
case class Product(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, items: Item*) extends Item

def price(it: Item): Double = it match {
  case Product(_, p) => p
  case Bundle(_, disc, its @ _*) => its.map(price _).sum * (100-disc) /100
  //  @            its
}


//  
val bun1 = Bundle("Father's day special", 20.0, Product("Massager", 188.0))
val bun2 = Bundle("Appliances on sale", 10.0, Product("Haier Refrigerato, 3000.0), Product("Geli air conditionor",2000.0)) //    1      scala> price(bun1) res5: Double = 150.4 //    2      scala> price(bun2) res6: Double = 4500.0

5、シーケンスパターンは、リストやArrayのようなシーケンスタイプにマッチングサンプルクラスのようにマッチングすることができる.
expr match {
    case List(0, _, _) => println("found it")
    case _ =>
}

//       
expr match {
    case List(0, _*) => println("found it")
    case _ => 
}

6、タプルモードマッチングタプル7、タイプモードはタイプテストとタイプ変換の簡単な代替とすることができる.
scala> def generalSize(x: Any) = x match {
     |   case s: String => s.length
     |   case m: Map[_, _] => m.size
     |   case _ => 1
     | }
generalSize: (x: Any)Int

scala> generalSize("abc")
res7: Int = 3

scala> generalSize(Map(1 -> 'a', 2 -> 'b'))
res8: Int = 2

scala> generalSize(Math.PI)
res9: Int = 1

サンプルクラスcase修飾子を有するクラスをサンプルクラス(case class)と呼ぶ.この修飾子は、Scalaコンパイラが自動的にクラスに文法的な利便性を追加することができます.
  • サンプルクラスには、クラス名と一致するファクトリメソッドが追加されます.newキーワードを使わずにこのクラスを作成できます.
  • サンプルクラスパラメータリストのすべてのパラメータは、val接頭辞を暗黙的に取得するため、フィールドとして維持される.
  • コンパイラは、サンプルクラスにメソッドtoString、hashCode、およびequalsの実装を追加した.

  • これらの利便性の代価は、case修飾子を書かなければならず、サンプルクラスおよびオブジェクトは、追加の方法および各コンストラクタパラメータに暗黙のフィールドを追加することによって大きくなることである.サンプルクラスは、モードマッチングに最適化された特殊なクラスです.
    クラスを閉じる
    閉じたクラスは、クラス定義が存在するファイル以外に新しいサブクラスを追加することはできません.パターンマッチングに使用されるもう一つの役割は、サンプルクラスでパターンマッチングを行う場合、コンパイラに可能なすべての選択がリストされていることを確認してもらいたいということです.この目的を達成するには、サンプルクラスの汎用スーパークラスをsealedと宣言する必要があります.閉じたクラスから継承されたサンプルクラスをマッチングすると、コンパイラは警告情報を通知することによって欠落したモードの組合せを識別します.例を挙げます.
    sealed abstract class Amount
    
    case class Dollar(value: Double) extends Amount
    case class Euro(value: Double) extends Amount
    case class Currency(value: Double, unit: String) extends Amount
    
    def describe(a: Amount): String = a match {
        case Dollar(_) => "Dollar"
        case Euro(_) => "Euro"
    }
    
    //          
    //warning: match may not be exhaustive.
    //It would fail on the following input: Currency(_, _)
    // def describe(a: Amount): String = a match {
    // ^
    //describe: (a: Amount)String

    コンパイラが警告メッセージを行わないようにするには、一致するセレクタ式に@unchecked注記を追加する必要があります.このようにdef describe(a: Amount): String = (a: @unchecked) match {です.クラスが閉じている場合、コンパイラのすべてのサブクラスが知られているため、コンパイラはモード文の整合性をチェックすることができます.すべての(同じグループ)サンプルクラスを閉じたクラスまたは特質に拡張するのは良い方法です.
    Optionタイプ
    標準クラスライブラリのOptionタイプは、存在する可能性があり、存在しない可能性のある値をサンプルクラスで表します.Some(value)の形式であってもよく、valueは実際の値である.欠落した値を表すNoneオブジェクトであってもよい.Scalaコレクションクラスのいくつかの標準操作により、オプション値が生成されます.たとえばScalaのMapのgetメソッドでは,指定キーが見つかった場合にSome(value)が生成され,指定キーが見つからない場合にNoneが生成される.例を次に示します.
    scala> val capitals = Map("France" -> "Paris",
         | "Japan" -> "Tokyo", "China" -> "Beijing")
    capitals: scala.collection.immutable.Map[String,String] = Map(France -> Paris, Japan -> Tokyo, China -> Beijing)
    
    scala> capitals get "France"
    res2: Option[String] = Some(Paris)
    
    scala> capitals get "North Pole"
    res3: Option[String] = None

    サンプルクラスNoneの形式は、nullを使用して値が欠けていることを示すよりも、空の文字列の意図よりも明確です.Optionは汎用型をサポートします.例えば、Some(Paris)のタイプはOption[String]である.
    オプション値を分離する最も一般的な方法は、次のようにパターンマッチングによって行われます.
    scala> def showCapital(x: Option[String]) = x match {
         |   case Some(s) => s
         |   case None => "?"
         | }
    showCapital: (x: Option[String])String
    
    scala> showCapital(capitals get "Japan")
    res5: String = Tokyo
    
    scala> showCapital(capitals get "France")
    res6: String = Paris
    
    scala> showCapital(capitals get "China")
    res7: String = Beijing
    
    scala> showCapital(capitals get "North Pole")
    res8: String = ?

    Scalaは、値がオプションであることを示すためにOptionの使用を奨励する.このオプション値を処理する方法にはJavaを超えるいくつかの利点がある.
    Option[String]         String,  String           null      
         null        null           Scala       ,      Option[String]   ,      String  ,        。
    

    参考資料
    ところでパターンマッチング(1):パターンとは何ですか.
    転載は作者Jason Dingとその出所GitCafeブログホームページを明記してください(http://jasonding1354.gitcafe.io/)Githubブログホームページ(http://jasonding1354.github.io/)CSDNブログ(http://blog.csdn.net/jasonding1354)簡書ホームページ(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)Google検索jasonding 1354私のブログのホームページに入ります