2013-01-23 11 views
37

私のカスタム例外タイプはcase classですか?例外はケースクラスですか?

プラス側では、私はエクストラクタを取得します。

マイナス側では、平等セマンティクスが正しくありません。しかし、私はequalsを上書きすることでそれを避けることができます。

概念レベルでは、それを作るには意味がありますcase class es?

+6

@TravisBrown:あなたはケースクラスを作成しないように十分な理由を持っている場合しかし、あなたは適用を解除する通常のクラスとで上記のサンプルと同じにarchieveことができ、(デイブ・グリフィスの答えを参照してください)私は答えが明白でなければならないことを知っていると思うので、建設的ではありません。 –

+0

私が探しているのは、適用と適用解除を伴うコンパニオンのようなケースクラスを作成するマクロですが、他のものは特に継承制限なしでは作成されません。これは他の場所でも便利です。 –

答えて

32

これは当然のことながら主観的ですが、私の意見では、例外クラスをケースクラスとして持つのがよい方法です。 主な根拠は、例外をキャッチするとパターンマッチングが行われ、パターンマッチングで使用するケースクラスがはるかに良いということです。ここで はcatchブロックでパターンマッチングのフルパワーを使用する能力のadvantadgeをとる例です、ケースクラスの例外使用している場合:この例では

object IOErrorType extends Enumeration { 
    val FileNotFound, DeviceError, LockedFile = Value 
} 
case class IOError(message: String, errorType: IOErrorType.Value) extends Exception(message) 

def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound) } 

try { 
    doSomeIO() 
} catch { 
    case IOError(msg, IOErrorType.FileNotFound) => 
    println("File not found, please check the path! (" + msg + ")") 
} 

を、私たちは一つだけ例外がありますが、それは含まれていerrorTypeフィールドは、発生した正確なエラータイプを知りたいときに使用します(通常、これは例外の階層構造をモデルにしていますが、これは良い例または悪い例ではありません)。 IOErrorはケースクラスなので、エラータイプIOErrorType.FileNotFoundの例外のみをキャッチするためにcase IOError(msg, IOErrorType.FileNotFound)を簡単に実行できます。私たちがケースクラスで無料で入手できるエクストラクタがなければ、毎回例外をキャッチして、実際には興味がない場合に備えて再作成する必要があります。これは間違いなく冗長です。

ケースクラスでは、等価セマンティクスが正しくないと言います。私はそうは思わない。 例外クラスの作者は、等価セマンティクスが意味を成すものを決定します。結局のところ、例外をキャッチすると、キャッチブロックは通常、型だけに基づいてどの例外をキャッチするかを決定しますが、私の例のように、フィールドの値などに基づいている可能性があります。要点は、例外クラスの等価セマンティクスはそれとはほとんど関係がないということです。

17

例外クラスを作成することによって失う共通のイディオムは、エラー条件のより大きな特異性を示すためにサブクラス化された例外のサブクラス階層を作成するパターンです。ケースクラスはサブクラス化できません。

+3

良い点。しかし、必要に応じて抽象的な例外の種類(特性や抽象クラス)の階層を作成し、すべてのリーフタイプをケースクラスにすることができます。これには、階層全体を「所有」する必要があります。つまり、クライアントコードが例外クラスを拡張することは想定されていません。そうでない場合は、例外のケースクラスを使用することが実際には最良の考えではないかもしれません。 –

+2

共通の特性を定義することはできますが、 –

+3

ケースクラスはサブクラス化できます。サブクラスがケースクラスそのものになることはできません。 –

1

私はRégisJean-Gillesの回答が気に入っています。 - 「何私は

object IOErrorType extends Enumeration { 
    val FileNotFound, DeviceError, LockedFile = Value 
} 
object IOError { 
    def unapply(err: IOError): Option[(String, IOErrorType.Value)] = Some(err.message, err.errorType) 
} 
class IOError(val message: String, val errorType: IOErrorType.Value) extends Exception(message) 

def doSomeIO() { throw new IOError("Oops, file not found!", IOErrorType.FileNotFound) } 

try { 
    doSomeIO() 
} catch { 
    case IOError(msg, IOErrorType.FileNotFound) => 
    println("File not found, please check the path! (" + msg + ")") 
} 
関連する問題