Scalaのパターンマッチングシステムでの比較演算子の使用


148

Scalaのパターンマッチングシステムを使用して比較を照合することはできますか?例えば:

a match {
    case 10 => println("ten")
    case _ > 10 => println("greater than ten")
    case _ => println("less than ten")
}

2番目のケースステートメントは違法ですが、「aがいつより大きいか」を指定できるようにしたいと思います。


1
これは、関数がtrueと評価されるかどうかを確認するためにも使用できます。たとえば、case x if x.size > 2 => ...
tstenner

2
理解しておくべき重要なことは、=>演算子の左側にある「パターン」は実際には「パターン」であることです。最初のケース式の10は整数リテラルではありません。したがって、左側で(>アプリケーションのisOdd(_)をチェックまたは言うなどの)操作を実行することはできません。
Ustaman Sangat 2013

回答:


292

ガード、つまりifパターンの後にブール式とブール式を追加できます。

a match {
    case 10 => println("ten")
    case x if x > 10 => println("greater than ten")
    case _ => println("less than ten")
}

編集:注意、これはより多くのパットに表面的に異なるよりであることをif した後=>、パターンが原因ではないだろうガードが真でない場合に一致します。


3
ベン、良い答えです。パターンガードの重要性をよく表しています。
JeffV

32

述語をmatch句に組み込む方法を尋ねた質問の精神に対する非回答として、この場合、述語はの前に除外できますmatch

def assess(n: Int) {
  println(
    n compare 10 match {
      case 0 => "ten"
      case 1 => "greater than ten"
      case -1 => "less than ten"
    })
}

ここで、のドキュメントでscala.math.Ordering.compare(T, T)等しくない結果がゼロより大きい、ゼロ未満になることのみ約束しています。Java Comparable#compareTo(T)はScalaと同様に指定されます。Scalaの現在の実装のように、正の値と負の値にそれぞれ1と-1を使用するのは慣習的なことですが、実装が下から変更されるリスクがないと、このような仮定を行うことはできません。


5
これを実際の解決策として提案するかどうかはわかりませんが、文書化されていない規則や前提に依存するものはお勧めしません。
ベンジェームス

1
丁度。だから私は「なんらかのリスクなしにそのような仮定をすることはできない」と書いて、私の答えを「無回答」とみなしました。これは、考慮すべき興味深い理由 compare()compareTo()0、1、および-1彼らの終域として指定しないでください。
seh

4
Math.signum(n compare 10)は、-1、0または1を保証します
richj

1
今朝は私がそのほとんどを確認六年問題の実装は別のタイプから移動していても、私のオリジナルの答えを書いた後、Scalaはまだ戻っ-1、0、または1のことに留意動作を維持
SEH

2
有効な答えですが、個人的に私はこれが好きではありません。0、1、-1の意味を忘れるのは簡単です。
DanGordon 2016年

21

私の意見では、ガードを追加するよりもはるかに読みやすいソリューションです。

(n compare 10).signum match {
    case -1 => "less than ten"
    case  0 => "ten"
    case  1 => "greater than ten"
}

ノート:

  • Ordered.compareこれがそれより小さい場合は負の整数を返し、それより大きい場合、および0等しい場合は正の整数を返します 。
  • Int.signum以下からの出力を圧縮compareする-1負の数(10未満)のために、1正の(10を超える)のために、または0ゼロのためには、(10に等しいです)。

1

上記のすべてと以下の答えは元の質問に完全に回答しますが、いくつかの追加情報はドキュメントhttps://docs.scala-lang.org/tour/pattern-matching.htmlで見つけることができますが、それらは私のケースに適合しませんでしたしかし、このstackoverflow回答はGoogleでの最初の提案であるため、上記の質問のコーナーケースである私の回答を投稿したいと思います。
私の質問は:

  • 関数の引数を持つマッチ式でガードを使用するにはどうすればよいですか?

これは言い換えることができます:

  • 関数の引数を持つ一致式でifステートメントを使用するにはどうすればよいですか?

答えは以下のコード例です:

    def drop[A](l: List[A], n: Int): List[A] = l match {
      case Nil => sys.error("drop on empty list")
      case xs if n <= 0 => xs
      case _ :: xs => drop(xs, n-1)
    }

Scalaのフィドルへのリンク:https://scalafiddle.io/sf/G37THif/2 あなたが見ることができるようにcase xs if n <= 0 => xsステートメントでは、guard(if)ステートメントでn(関数の引数)を使用できること。

これが私のような人に役立つことを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.