1. ホーム
  2. swift

引数を持つ列挙型のif-else比較の方法 [重複]について

2023-10-12 07:23:46

質問

言語 : Swift2.3

例えば......様々な種類の列挙型を紹介しましょう。

enum Normal {
    case one
    case two, three
}

enum NormalRaw: Int {
    case one
    case two, three
}

enum NormalArg {
    case one(Int)
    case two, three
}   

Switch はこのように3つの列挙型で使うことができます。

var normal: Normal = .one
var normalRaw: NormalRaw = .one
var normalArg: NormalArg = .one(1)

switch normal {
    case .one: print("1")
    default: break
}

switch normalRaw {
    case .one: print(normalRaw.rawValue)
    default: break
}

switch normalArg {
    case .one(let value): print(value)
    default: break
}

if-else文で比較できるのは NormalNormalRaw については、エラーメッセージが表示されます。 NormalArg というエラーメッセージが表示され、コードを実行することができません。

二項演算子 '==' は、以下の型のオペランドには適用できません。 NormalArg_

以下はコード例です。

if normal == .two { // no issue
    .. do something
}

if normalRaw == .two { // no issue
    .. do something
}

if normalArg == .two { // error here (the above message)
    .. do something
}

if normalArg == .one(_) { // error here (the above message)
    .. do something
}

if normalArg == .three { // error here (the above message)
    .. do something
}

何かアイデアはありますか?私はこのコードで本当に何もしていないのですが、なぜ比較ができないのか不思議に思っています。

どのように解決するのですか?

コツは、実際に==でチェックするのではなく、その前に case キーワードを使用して、if 文の中で 1 つの = を併用することです。これは最初のうちは少し直感に反しますが、ちょうど if let と同じように、すぐに慣れることができます。

enum Normal {
    case one
    case two, three
}

enum NormalRaw: Int {
    case one = 1
    case two, three
}

enum NormalArg {
    case one(Int)
    case two, three
}


let normalOne = Normal.one
let normalRawOne = NormalRaw.one
let normalArgOne = NormalArg.one(1)

if case .one = normalOne {
    print("A normal one") //prints "A normal one"
}

if case .one = normalRawOne {
    print("A normal \(normalRawOne.rawValue)") //prints "A normal 1"
}

if case .one(let value) = normalArgOne {
    print("A normal \(value)") //prints "A normal 1"
}

ポイントは、Swiftでは、enumが生の型を使用する場合、または関連する値がない場合、無料でenumの等式を得るだけです(試してみてください、同時に両方を持つことはできません)。しかし、Swift は関連する値を持つケースを比較する方法を知りません - 私はそれがどのようにできるかを意味します。この例を見てみましょう。

Normal.one == .one //true
Normal.one == .two //false

NormalRaw.one == .one //true
NormalRaw.one == .two //false

NormalArg.one(1) == .one(1) //Well...?
NormalArg.one(2) == .one(1) //Well...?
NormalArg.one(1) == .two //Well...?

これで、なぜこれが箱から出してもうまくいかないのかがはっきりしたのではないでしょうか。

class Special {
    var name: String?
    var special: Special?
}

enum SpecialEnum {
    case one(Special)
    case two
}

var special1 = Special()
special1.name = "Hello"

var special2 = Special()
special2.name = "World"
special2.special = special1

SpecialEnum.one(special1) == SpecialEnum.one(special2) //Well...?

そのため、値を関連付けたenumが必要な場合は、自分でenumにEquatableプロトコルを実装する必要があります。

enum NormalArg: Equatable {
    case one(Int)
    case two

    static func ==(lhs: NormalArg, rhs: NormalArg) -> Bool {
        switch (lhs, rhs) {
        case (let .one(a1), let .one(a2)):
            return a1 == a2
        case (.two,.two):
            return true
        default:
            return false
        }
    }
}