2014-07-04 24 views
5

Ai đó có thể giải thích những gì đang xảy ra trong mã dưới đây? Nó tạo ra một cấu trúc Either có hai kiểu tùy chọn và (cố gắng) trả lại bất kỳ kiểu nào không phải là nil, hoặc đầu tiên nếu cả hai không phải là số không. Tuy nhiên, nó cư xử lạ lùng khi đi qua con số không đen như trái ngược với một biến con số không. Tôi không thể hiểu tại sao b4 trong ví dụ này cư xử như nó ...Thực hiện cấu trúc "Hoặc" trong Swift

struct Either <T1, T2> { 
    let first: T1? 
    let second: T2? 

    init(first: T1?, second: T2?) { 
     self.first = first 
     self.second = second 
    } 

    func either() -> Bool { 
     return (self.first != nil) || (self.second != nil) 
    } 

    func which() -> Any? { 
     if self.first != nil { 
      return self.first 
     } else if self.second != nil { 
      return self.second 
     } 
     return nil 
    } 
} 

var s1: String? = nil 
var s2: Int? = nil 

let b1 = Either(first: s1, second: s2) 
b1.either() // false 
b1.which() // {nil} 

s1 = "Hello" 
let b2 = Either(first: s1, second: s2) 
b2.either() // true 
b2.which() // {Some Hello} 

s1 = nil 
s2 = 7 
let b3 = Either(first: s1, second: s2) 
b3.either() // true 
b3.which() // {Some 7} 

// all as expected, however 
let b4 = Either(first: nil, second: nil) 
b4.either() // true !!! <<<<<<<<<<<<<<<<<< 
b4.which() // {nil} 

tôi nghĩ rằng nó đã làm với "Tùy chọn Tùy chọn ", nhưng tôi không chắc nó hoạt động như mong đợi.

Trả lời

6

này đã được cố định trong bản Beta 3, trường hợp cuối cùng tại gây nên một cách chính xác một lỗi biên dịch buộc bạn phải xác định loại generic explicitely

Vấn đề là trong các loại - khi tạo Either từ literals:

let b4 = Either(first: nil, second: nil) 

thì trình biên dịch không thể suy ra loại cho thông số nil. Nếu bạn kiểm tra trình gỡ lỗi, bạn sẽ thấy rằng loại được phỏng đoán là một loại được gọi là _Nil.

(lldb) p b4 
(SwiftConsole.Either<_Nil, _Nil>) $R1 = { 
    first = Some 
    second = Some 
} 

Hiện tại, đây là loại chấp nhận nil nhưng không phải là loại tùy chọn.

let x: _Nil = nil //this is not an optional 

Các initialiser đang thực hiện một tùy chọn của nó, do đó làm cho một giá trị Optional.Some(nil) và bởi vì đó là một giá trị .Some(...), so sánh nó với nil sẽ false.

Tôi không thấy bất kỳ cách giải quyết chung chung dễ dàng nhưng trong trường hợp này nó sẽ giúp để xác định kiểu generic một cách rõ ràng:

let b4 = Either<String, Int>(first: nil, second: nil) 

tôi đề nghị bạn thông báo lỗi bởi vì đây chỉ là ngớ ngẩn. Thay vì suy ra một số loại đặc biệt dẫn đến hành vi không xác định, trình biên dịch thay vào đó sẽ kích hoạt một lỗi.

Vấn đề tương tự sẽ phát sinh với loại Any vì nó cũng có thể chấp nhận nil mà không phải là tùy chọn.

let x: Any = nil //this is not an optional 

Either<Any, Any>(first: nil, second: nil).which() //true !!! 

Edit: này sẽ được cố định trong Beta 3. nil sẽ được thực hiện một chữ, _Nil loại sẽ được gỡ bỏ và _Any sẽ không chấp nhận nil nữa.

Đã xác nhận tại đây: https://devforums.apple.com/thread/234463?tstart=0

+0

Cảm ơn bạn đã liên kết, @Sulthan. Việc thêm các mệnh đề 'if let' mà họ đề nghị không tạo ra sự khác biệt nào, nhưng lời nhận xét đóng của họ" Có lẽ không pha trộn các tùy chọn và Bất kỳ "là ... tốt ... ít hơn lý tưởng! Tôi thấy điều đáng lo ngại là tôi không thể dự đoán/hợp lý hoá _why_ điều này xảy ra. – Grimxn

+0

'let b4 = Hoặc là (thứ nhất: không, giây: không)' hoạt động, như bạn đề nghị. Horrid. – Grimxn

+0

@Grimxn Tôi vừa mới đến Xcode và phải chỉnh sửa câu trả lời vì vấn đề phức tạp hơn tôi nghĩ ban đầu. – Sulthan

Các vấn đề liên quan