Swift: kiểm tra giá trị tùy chọn trong trường hợp chuyển mạch


89

Trong Swift, làm cách nào tôi có thể viết một trường hợp trong một câu lệnh switch kiểm tra giá trị được chuyển sang nội dung của một tùy chọn , bỏ qua trường hợp nếu tùy chọn chứa nil?

Đây là cách tôi tưởng tượng nó có thể trông như thế nào:

let someValue = 5
let someOptional: Int? = nil

switch someValue {
case someOptional:
    // someOptional is non-nil, and someValue equals the unwrapped contents of someOptional
default:
    // either, someOptional is nil, or someOptional is non-nil but someValue does not equal the unwrapped contents of someOptional
}

Nếu tôi chỉ viết nó chính xác như thế này, trình biên dịch sẽ phàn nàn rằng someOptionalkhông được mở gói, nhưng nếu tôi mở nó một cách rõ ràng bằng cách thêm !vào cuối, tất nhiên tôi sẽ gặp lỗi thời gian chạy bất kỳ lúc nào someOptionalnil. Việc thêm ?thay vì !sẽ có ý nghĩa đối với tôi (theo tinh thần của chuỗi tùy chọn, tôi cho là vậy), nhưng không làm cho lỗi trình biên dịch biến mất (nghĩa là không thực sự mở gói tùy chọn).

Câu trả lời:


112

Tùy chọn chỉ là enumnhư thế này:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)

    // ...
}

Vì vậy, bạn có thể đối sánh chúng như các mẫu đối sánh "Giá trị được liên kết" thông thường :

let someValue = 5
let someOptional: Int? = nil

switch someOptional {
case .Some(someValue):
    println("the value is \(someValue)")
case .Some(let val):
    println("the value is \(val)")
default:
    println("nil")
}

Nếu bạn muốn đối sánh từ someValue, sử dụng biểu thức bảo vệ :

switch someValue {
case let val where val == someOptional:
    println(someValue)
default:
    break
}

Và đối với Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}

4
Lưu ý rằng trong Swift 3, một số / không được chữ thường, ví dụ bạn muốn sử dụng .some thay vì .Some
Adam

52

Kể từ Xcode 7 (từ ghi chú phát hành beta 1), “một x?mẫu mới có thể được sử dụng để so khớp mẫu với các tùy chọn như một từ đồng nghĩa với .Some(x)”. Điều này có nghĩa là trong Xcode 7 trở lên, biến thể sau của câu trả lời rintaro cũng sẽ hoạt động:

let knownValue = 5

switch someOptional {
case knownValue?:
    // Contents of someOptional are knownValue, defined above.
case let otherValue?:
    // Contents of someOptional are *any* non-nil value not already tested for.
    // Unwrapped contents are assigned to otherValue for use inside this case.
default:
    // someOptional is nil.
}

3
Câu hỏi là về việc so khớp một giá trị không tùy chọn với một tùy chọn, câu trả lời này là ngược lại.
Martin R

2
Đúng, tuy nhiên câu trả lời này ban đầu được viết bởi OP như một bản cập nhật cho câu hỏi, vì vậy đối với ông, đây là một giải pháp khả thi không thể chối cãi; Tôi vừa chuyển nó sang câu trả lời trên wiki cộng đồng. Có lẽ @GeorgeWS có thể làm rõ lý do tại sao việc chuyển đổi công tắc & hộp điều khiển hoạt động cho trường hợp sử dụng của anh ấy?
Slipp D. Thompson

2
Tôi hơi bị lạc lõng. sự khác biệt giữa hai trường hợp đầu tiên của bạn là gì? someValue?là một số giá trị được xác định khác, nhưng case let val?chỉ là phiên bản chưa được bao bọc an toàn của someOptional?!
Honey,

@Honey Đây không phải là một ví dụ mã trong thế giới thực; nó chỉ đơn giản là một biến thể trong câu trả lời của rintaro. Vì vậy, hãy hỏi anh ấy / cô ấy câu hỏi đó— câu trả lời của tôi về mặt chức năng tương đương với mã trong mã của anh ấy / cô ấy. Nếu bạn muốn hỏi rintaro, tôi tin rằng câu trả lời sẽ là 1. nó phản ánh những gì trong các tài liệu Apple được liên kết; 2. nó chỉ thể hiện cú pháp; nó không hoàn thành một mục tiêu tính toán riêng biệt hoặc logic nghiệp vụ.
Slipp D. Thompson

@Honey Ngoài ra, câu trả lời của rintaro ban đầu được viết cho Swift 1.x và được cập nhật cho Swift 2. Có thể phiên bản letkhông còn biên dịch nữa. Tôi không thể nhớ ngay bây giờ tại sao nó sẽ hoạt động trở lại trong ngày.
Slipp D. Thompson

9

Trong Swift 4, bạn có thể sử dụng Tùy chọn: ExpressibleByNilLiteral của Apple để kết thúc tùy chọn

https://developer.apple.com/documentation/swift/optional

Thí dụ

enum MyEnum {
    case normal
    case cool
}

một số

let myOptional: MyEnum? = MyEnum.normal

switch smyOptional {
    case .some(.normal): 
    // Found .normal enum
    break

    case .none: 
    break

    default:
    break
}

không ai

let myOptional: MyEnum? = nil

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    // Found nil
    break

    default:
    break
}

mặc định

let myOptional: MyEnum? = MyEnum.cool

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Enum với giá trị

enum MyEnum {
    case normal(myValue: String)
    case cool
}

một số giá trị

let myOptional: MyEnum? = MyEnum.normal("BlaBla")

switch smyOptional {
case .some(.normal(let myValue)) where myValue == "BlaBla":
    // Here because where find in my myValue "BlaBla"
    break

// Example for get value
case .some(.normal(let myValue)):
    break

// Example for just know if is normal case enum
case .some(.normal):
    break

case .none:
    break

default:

    break
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.