2015-01-03 20 views
10

Tôi đang cố gắng triển khai tiện ích mở rộng Dictionary và tôi muốn xử lý các giá trị tùy chọn. Nhưng bất cứ điều gì tôi làm, nếu tôi sử dụng phương pháp của tôi trên một từ điển [String: String?], nó không tùy ý ràng buộc giá trị. Làm thế nào để bạn viết một phần mở rộng cho một từ điển xử lý một cách duyên dáng các giá trị tùy chọn?Cách viết tiện ích mở rộng từ điển xử lý các giá trị tùy chọn


xem xét việc gia hạn sau đây:

extension Dictionary { 
    func someMethod() { 
     for (key, value) in self { 
      if let valueString = value as? String { 
       println(" \(key) = \(valueString)") 
      } else { 
       println(" \(key) = \(value) cannot be cast to `String`") 
      } 
     } 
    } 
} 

Vì vậy, xem xét đoạn mã sau:

let dictionary: [String: AnyObject?] = ["foo": "bar"] 
dictionary.someMethod() 

Và nó tò mò báo cáo

foo = Optional(bar) cannot be cast to `String` 

tôi có thể viết một tổ chức phi mở rộng phương pháp xử lý dict tham số ion với các giá trị tùy chọn, nhưng không thấy cách làm như một phần mở rộng của Dictionary.

+0

tôi có thể giải thích lý do tại sao nó không hoạt động khi bạn dường như mong đợi. Khi áp dụng cho một tùy chọn, 'as',' is', 'as?', Và '==' (và các bộ so sánh khác) có ý nghĩa đặc biệt: chúng được áp dụng cho điều được bọc. Lý do tại sao 'nếu để valueString = value là? Chuỗi' không làm những gì bạn mong đợi là ở thời gian biên dịch, chúng tôi không biết rằng 'giá trị' _is_ một Tùy chọn, và vì vậy chúng tôi không sử dụng ý nghĩa đặc biệt của' as' được áp dụng cho Tùy chọn. Chúng tôi cố gắng truyền _itself_ tùy chọn thành chuỗi và tất nhiên là không thành công; bạn không thể truyền _itself_ tùy chọn cho bất kỳ thứ gì. – matt

+1

Như bạn đã nói, tôi tin rằng, Swift dường như mời sử dụng các phương thức ví dụ, nhưng sức mạnh thực sự nằm trong các chức năng toàn cầu cấp cao nhất, bởi vì chúng cho phép bạn xây dựng một ràng buộc chung cho phép loại chính xác thông qua lưới, vì nó là. Từ điển là một generic, và bạn không thể thêm các ràng buộc thêm vào một generic, vì vậy bạn sẽ không bao giờ có thể làm điều này với một phương thức instance trong một phần mở rộng. – matt

Trả lời

4

Bạn có thể làm điều này với sự phản ánh. Không đòi hỏi mã nhiều hơn bạn đã có:

extension Dictionary 
{ 
    func someMethod() 
    { 
     for (key, value) in self 
     { 
      var valueRef = _reflect(value) 

      while valueRef.disposition == .Optional && valueRef.count > 0 && valueRef[0].0 == "Some" 
      { 
       valueRef = valueRef[0].1 
      } 

      if let valueString: String = valueRef.value as? String 
      { 
       print(" \(key) = \(valueString)") 
      } 
      else 
      { 
       print(" \(key) = \(value) cannot be cast to `String`") 
      } 
     } 
    } 
} 

let dictionary: [String : AnyObject?] = ["foo" : "bar"] 
dictionary.someMethod() 

Returns

foo = bar 

let dictionary: [String : AnyObject?] = ["foo" : nil] 
dictionary.someMethod() 

Returns

foo = nil cannot be cast to `String` 

let dictionary: [String : AnyObject?] = ["foo" : UIViewController()] 
dictionary.someMethod() 

Returns

foo = Optional(<UIViewController: 0x7fee7e819870>) cannot be cast to `String` 
0

Tôi không gặp vấn đề gì khi tôi chèn ': Chuỗi?' ngay sau khi valueString như hình dưới đây:

extension Dictionary { 
    func someMethod() -> Bool { 
     for (key, value) in self { 
      if let valueString:String? = value as? String { 
       println(" \(key) = \(valueString)") 
      } else { 
       println(" \(key) = \(value) cannot be cast to `String`") 
       return false 
      } 
     } 
     return true 
    } 
} 

func doSomething() { 
    let dictionary: [String: AnyObject?] = ["foo": "bar"] 
    if dictionary.someMethod() { 
     println("no problems") 
    } else { 
     println("casting issues") 
    } 
} 
+1

Thú vị. Khi tôi làm điều đó, nó không thất bại và rơi vào "không thể cast" (tức là nó trả về 'true', nhưng' valueString' luôn luôn là 'nil', ngay cả khi có một giá trị được cung cấp. – Rob

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