2015-04-06 22 views
18

Chạy đoạn mã sau trong sân chơi cho một lỗi:So sánh mảng tùy chọn

let a: [Int]? = [1,2] 
let b: [Int]? = [1,2] 
a == b // value of optional type '[Int]?' not unwrapped; did you mean to use '!' or '?'? 

Trong khi làm một cái gì đó tương tự cho một 'đơn giản' loại tùy chọn hoạt động:

var x: Int? = 10 
var y: Int? 
x == y // false 

lý do là gì đằng sau trường hợp đầu tiên, của mảng tùy chọn, không được phép? Tại sao Swift không thể xem trước nếu một trong hai bên nếu nil (.None) và sau đó nếu không, hãy so sánh mảng thực tế.

+0

Bạn đang sử dụng phiên bản Swift nào? Trường hợp thứ hai của bạn cung cấp cho tôi lỗi của 'Biến 'y' được sử dụng trước khi được khởi tạo ' – aganders3

+0

trùng lặp có thể có của [Lỗi Swift so sánh hai mảng tùy chọn] (http://stackoverflow.com/questions/28830411/swift-error-comparing- hai mảng-of-optionals) – milo526

+0

Xin lỗi, tôi đã đánh máy từ một sân chơi. Đã sửa câu hỏi. –

Trả lời

29

Lý do nó hoạt động với nhiều loại đơn giản là bởi vì có một phiên bản của == được định nghĩa cho optionals có chứa loại mà là Equatable:

func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool 

Nhưng trong khi IntEquatable, Array không (vì nó có thể chứa một cái gì đó mà không phải là tương đương - trong trường hợp đó làm thế nào nó có thể được). Tất cả các điều khoản Equatable đều có nhà điều hành ==, nhưng không phải tất cả mọi thứ đều có nhà điều hành ==Equatable.

Bạn có thể viết một phiên bản đặc biệt hợp cụ thể của == đặc biệt cho mảng tùy chọn có chứa loại equatable:

func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool { 
    switch (lhs,rhs) { 
    case (.Some(let lhs), .Some(let rhs)): 
     return lhs == rhs 
    case (.None, .None): 
     return true 
    default: 
     return false 
    } 
} 

Bạn cũng có thể khái quát này để bao gồm bất kỳ bộ sưu tập có chứa yếu tố equatable:

func ==<C: CollectionType where C.Generator.Element: Equatable> 
    (lhs: C?, rhs: C?) -> Bool { 
    switch (lhs,rhs) { 
    case (.Some(let lhs), .Some(let rhs)): 
     return lhs == rhs 
    case (.None, .None): 
     return true 
    default: 
     return false 
    } 
} 
+1

Có thể có lý do nào khiến Apple không thực hiện nó trực tiếp? –

+0

Ngoài ra tôi đang gặp rắc rối với func thứ hai bạn đề xuất. Khi so sánh [Chuỗi]? đến nil, trình biên dịch trả về 'sử dụng toán tử không rõ ràng =='. Tôi sẽ đề nghị chỉ sử dụng cái đầu tiên. –

+0

Nhưng tại sao trình biên dịch nhanh có thể giải quyết điều này: 'Tùy chọn ([1]) == Tùy chọn ([1])' – benrudhart

6

thêm nhanh chóng 3 phiên bản của câu trả lời của Airspeed:

func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool { 
    switch (lhs,rhs) { 
    case (.some(let lhs), .some(let rhs)): 
    return lhs == rhs 
    case (.none, .none): 
    return true 
    default: 
    return false 
    } 
} 

func ==<C: Collection where C.Iterator.Element: Equatable>(lhs: C?, rhs: C?) -> Bool { 
    switch (lhs,rhs) { 
    case (.some(let lhs), .some(let rhs)): 
    return lhs == rhs 
    case (.none, .none): 
    return true 
    default: 
    return false 
    } 
} 
0

Cách dễ nhất là không sử dụng mảng tùy chọn và sử dụng một mảng trống ([]) thay vì nil - trong trường hợp bạn không cần phân biệt giữa hai trường hợp đó.

let a = [1,2] 
let b = [1,2] 
let c = [] 
a == b 
b != c 

Nó hoạt động trong trường hợp của tôi khi tôi viết phần mở rộng Equatable cho cấu trúc. Thay vì sử dụng thuộc tính categories: [Category]? Tôi vừa thay đổi nó thành categories: [Category] và phân tích cú pháp các danh mục bị thiếu làm mảng trống ([]).