2014-10-29 12 views
11

tôi biết làm thế nào để tùy chỉnh các nhà khai thác nhị phân, như thế nàyLàm thế nào để tùy chỉnh các nhà khai thác ternary trong Swift

infix operator ** { associativity left precedence 170 } 
func ** (left: Double, right: Double) -> Double { 
    return pow(left, right) 
} 

Nhưng, làm thế nào để tùy chỉnh các nhà khai thác ternary trong Swift? Bất cứ ai có thể cho tôi một số ý tưởng? Cám ơn rất nhiều!

Trả lời

5

Toán tử bậc ba "true" chẳng hạn như _ ? _ : _ yêu cầu hỗ trợ ngôn ngữ. Swift cho phép tạo và tùy chỉnh các toán tử đơn và nhị phân.

Bạn có thể sử dụng kỹ thuật trong @ câu trả lời NateCook để làm cho một cặp các nhà khai thác nhị phân mà cùng nhau làm việc như một nhà điều hành ternary, nhưng họ vẫn đang khai thác nhị phân độc lập - bạn có thể sử dụng một trong hai ngày của riêng mình. (Ngược lại, _ ? _ : _chỉ một nhà điều hành ternary;. _ ? __ : _ không thể được sử dụng riêng)

Tất nhiên, tại sao dừng lại ở đó? Bạn có thể chuỗi các toán tử nhị phân hơn để tạo các toán tử bậc bốn, v.v. Đối với tín dụng thêm, hãy thử làm cho mình một nhà điều hành tàu vũ trụ mở rộng:

let c: String = a <=> b 
    |<| "a < b" 
    |=| "a = b" 
    |>| "a > b" 

(... nhưng xin vui lòng làm điều này như một bài tập học tập mà thôi, hoặc bất kỳ ai khác làm việc với mã bạn viết sẽ ghét bạn.)

18

Bạn có thể thực sự thực hiện việc này bằng cách khai báo hai toán tử riêng biệt hoạt động cùng nhau và sử dụng hàm được kết hợp cho một trong các toán tử.

Hãy tuyên bố một nhà điều hành ternary x +- y +|- z rằng sẽ kiểm tra các dấu hiệu của giá trị ban đầu x, và sau đó trả về giá trị thứ hai y nếu dấu là zero hoặc tích cực và giá trị cuối cùng z nếu dấu là tiêu cực. Tức là, chúng ta có thể viết:

let sign = -5 +- "non-negative" +|- "negative" 
// sign is now "negative" 

Chúng tôi sẽ bắt đầu bằng cách khai báo hai toán tử. Phần quan trọng là phải có ưu tiên cao hơn trên các nhà điều hành thứ hai - chúng tôi sẽ đánh giá phần đó đầu tiên và trả về một hàm:

infix operator +- { precedence 60 } 
infix operator +|- { precedence 70 } 

Sau đó xác định các chức năng - chúng tôi sẽ xác định thứ hai đầu tiên:

func +|-<T>(lhs: @autoclosure() -> T, rhs: @autoclosure() -> T)(left: Bool) -> T { 
    return left ? lhs() : rhs() 
} 

Phần quan trọng ở đây là chức năng này được curried - nếu bạn chỉ gọi nó với hai tham số đầu tiên, thay vì trả về giá trị T, nó trả về một hàm (left: Bool) -> T. Đó trở thành tham số thứ hai của hàm cho nhà điều hành đầu tiên của chúng tôi:

func +-<I: SignedIntegerType, T>(lhs: I, rhs: (left: Bool) -> T) -> T { 
    return rhs(left: lhs >= 0) 
} 

Và bây giờ chúng ta có thể sử dụng toán tử "ternary" của chúng tôi, như thế này:

for i in -1...1 { 
    let sign = i +- "" +|- "-" 
    println("\(i): '\(sign)'") 
} 
// -1: '-' 
// 0: '' 
// 1: '' 

Lưu ý: tôi đã viết a blog post on this subject với một ví dụ khác.

+1

'func + | -' có lẽ nên sử dụng autoclosures quá, để các thông số được đánh giá lazily, như với thông thường'?: '. Ngoài ra, trong khi điều này tạo ra một cái gì đó hoạt động giống như một toán tử bậc ba, người ta không thể thực sự sử dụng '?' Và ':' vì không phải trong số đó là một mã thông báo 'operator' hợp lệ trong nhanh chóng. – bames53

+0

Tôi vừa quay lại để chỉnh sửa! Và có, '?:' Chính nó không thể bị ghi đè. –

+0

Ví dụ tương tự tại đây: http://www.reddit.com/r/swift/comments/2fjwav/custom_ternary_operator/ –

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