2012-02-19 1 views
10

パターンマッチをもう一度行うと、Nilを使って空のリストをチェックすることができます。基本となる型が反復処理可能である場合は、あなたはまだナシを確認することができ、それが空集合、などのために中断します...以下のREPLセッションを参照してください:この種のバグパターンマッチングとNilを防ぐ方法

scala> val l: Iterable[Int] = List() 
l: Iterable[Int] = List() 

scala> l match { 
    | case Nil => 1 
    | case _ => 2 
    | } 
res0: Int = 1 

scala> val l: Iterable[Int] = Set() 
l: Iterable[Int] = Set() 

scala> l match { 
    | case Nil => 1 
    | case _ => 2 
    | } 
res2: Int = 2 

質問です - どのように私は、この種のを防ぐことができます問題の?明らかに、lが型Listの場合、バグはありません。そして、もしlがSet型であれば、それはコンパイルされません。しかし、リストを持つクラスがあり、このようにパターンを一致させる関数を定義すれば、代わりにジェネリック反復可能クラスを変更する人はいますか?このNil vs. _パターンは一般的に悪い考えですか?

+5

サブタイプは両刃の剣です。慎重に使用してください。 –

答えて

8

疑念を取り除くために、監視者をリストに変換してください。ここで

l.toList match { 
    case Nil => 1 
    case xs => 2 
} 
+1

リストでない場合のコンバージョンはどのくらい遅いですか? O(n)右? – dyross

+0

'.toSeq'も十分です。 '(Vector():Seq [Int])は{case Nil => 0}と一致します。 – retronym

+0

しかしこれは、 '' Nil.equals''がオーバーライドされ、 '' Nil''が空のseqと等しいことにのみ依存します。これは文書化されていないので、私はそれに頼ることはありません(あなたの答えに 'toSeq'を使って' toList'を使うほうが、魔法は少なくなります)。 –

11

一つの可能​​性は、ガードを使用することです。これを行うには

scala> val xs: Iterable[Int] = Set() 
xs: Iterable[Int] = Set() 

scala> xs match { case xs if xs.isEmpty => 1 case _ => 2 } 
res0: Int = 1 

もう一つの方法は、if-else式(あなただけをチェックするために1つのまたは2つの条件がある場合は最高の作品)を使用することです。

scala> if (xs.isEmpty) 1 else 2 
res1: Int = 1 
+0

if elseは私がそれをどうやってやったかです。ちょうど慣用的ではないようです。 – dyross

+0

Imhoパターンマッチングコレクションの最良の方法 – lisak

1

は別のオプション(しゃれ意図)である:

scala> val l: Iterable[Int] = List() 
l: Iterable[Int] = List() 

scala> l.headOption match { case None => 1; case Some(h) => 2 } 
res0: Int = 1 

これは、人気のList() match { case h :: t => ... }のようheadを得るためにあなたのパターンマッチの場合に有用であるが、それは、それは、リストのいませんIterableおよび::は、に失敗します。

私は、ヘッドを得るためにコレクションでパターンマッチングすることはかなり一般的だと思ったので、この回答を追加しました。そうでなければ、xs.isEmptyでチェックできます。

関連する問題