省略 - scala パターンマッチ if




パターンマッチング対if-else (6)

パフォーマンスに影響されない大部分のコードでは、if / elseにパターンマッチングを使用する理由がたくさんあります。

  • ブランチごとに共通の戻り値と型を強制します
  • 徹底的なチェック(Scalaのような)を持つ言語では、明示的にすべてのケースを考慮する必要があります(必要のないものは使用しないでください)
  • カスケードしたり、数が増えたり、ブランチが画面の高さよりも長くなったりすると(それが目に見えなくなる)、早期のリターンを防ぐことができなくなります。 余分なレベルのインデントがあると、スコープの内側にいることを警告します。
  • それは引き出す論理を特定するのに役立ちます。 この場合、コードは次のように書き換えられ、DRY、デバッグ、テスト可能になります。
val errorMessage = user.password == enteredPassword match {
  case true => "User is authenticated"
  case false => "Entered password is invalid"
}

println(errorMesssage)

if / elseブロックの実装は次のとおりです。

var errorMessage = ""

if(user.password == enteredPassword)
  errorMessage = "User is authenticated"
else
  errorMessage = "Entered password is invalid"

println(errorMessage)

はい、ブールチェックのような簡単なことについて、if式を使用することができると主張できます。 しかし、これはここでは関係がなく、2つ以上の分岐を持つ条件にはうまく対応しません。

あなたの懸念事項がメンテナンス性や可読性である場合、パターンマッチングはすばらしく、マイナーなものにも使うべきです!

私はスカラの初心者です。 最近、私は趣味のアプリを書いていて、多くの場合、if-elseの代わりにパターンマッチングを使用しようとしました。

user.password == enteredPassword match {
  case true => println("User is authenticated")
  case false => println("Entered password is invalid")
}

の代わりに

if(user.password == enteredPassword)
  println("User is authenticated")
else
  println("Entered password is invalid")

これらのアプローチは同じですか? 何らかの理由でそれらのうちの1つが他のものよりも優先的であるか?


両方のステートメントは、コードセマンティクスで同等です。 しかし、コンパイラが1つのケース( match )でより複雑な(したがって非効率的な)コードを作成する可能性があります。

パターンマッチングは、通常、ポリモーフィックな表現や、( unapplyされない)オブジェクトのコンポーネントへの分解など、より複雑な構造を分解するために使用されます。 私は単純なif-elseステートメントの代理として使用するようアドバイスしません。if -elseには何も問題ありませ

Scalaの式として使うことができることに注意してください。 したがって、あなたは書くことができます

val foo = if(bar.isEmpty) foobar else bar.foo

私は愚かな例をお詫びします。


私の環境(scala 2.12とjava 8)では、私は別の結果を得ています。 上記のコードでは、Matchが一貫して優れています。

timeIf:Long = 249 timeMatch:Long = 68


私は別の意見を述べるためにここに来ています:あなたが提供している具体例では、読む方がはるかに簡単なので、実際には2番目のスタイル(もっと...)

実際に、最初の例をIntelliJに入れると、2番目(if ... else ...)のスタイルに変更することを提案します。 IntelliJスタイルの提案は次のとおりです。

Trivial match can be simplified less... (⌘F1) 

Suggests to replace trivial pattern match on a boolean expression with a conditional statement.
Before:
    bool match {
      case true => ???
      case false => ???
    }
After:
    if (bool) {
      ???
    } else {
      ???
    }

間違いなく良い方法は、ブール値の盲目を避けるため、比較の結果ではなく、文字列に対して直接パターンマッチングすることです。 http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/

1つの欠点は、入力されたパスワードがシャドーされないようにするためにバッククォートを使用する必要があることです。

基本的には、型レベルで情報を伝えないので、ブール値を可能な限り扱わないようにする必要があります。

user.password match {
    case `enteredPassword` => Right(user)
    case _ => Left("passwords don't match")
}

class MatchVsIf {
  def i(b: Boolean) = if (b) 5 else 4
  def m(b: Boolean) = b match { case true => 5; case false => 4 }
}

私はなぜあなたが長くてぎこちない二番目のバージョンを使いたいのか分かりません。

scala> :javap -cp MatchVsIf
Compiled from "<console>"
public class MatchVsIf extends java.lang.Object implements scala.ScalaObject{
public int i(boolean);
  Code:
   0:   iload_1
   1:   ifeq    8
   4:   iconst_5
   5:   goto    9
   8:   iconst_4
   9:   ireturn

public int m(boolean);
  Code:
   0:   iload_1
   1:   istore_2
   2:   iload_2
   3:   iconst_1
   4:   if_icmpne   11
   7:   iconst_5
   8:   goto    17
   11:  iload_2
   12:  iconst_0
   13:  if_icmpne   18
   16:  iconst_4
   17:  ireturn
   18:  new #14; //class scala/MatchError
   21:  dup
   22:  iload_2
   23:  invokestatic    #20; //Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
   26:  invokespecial   #24; //Method scala/MatchError."<init>":(Ljava/lang/Object;)V
   29:  athrow

そしてそれはまた試合のためにもっとたくさんのバイトコードです。 それはかなり効率的です(ここでは起こり得ないエラーがスローされない限りボクシングはありません)が、コンパクトさとパフォーマンスのためには/ elseが有利else 。 ただし、一致を使用することでコードの明瞭度が大幅に向上した場合は、パフォーマンスが重要であることが分かっている稀なケースを除き、その差異を比較したい場合があります。







scala