2014-10-29 12 views
11

So come personalizzare operatori binari, come questoCome personalizzare gli operatori ternari a Swift

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

Ma, come personalizzare gli operatori ternari a Swift? Qualcuno può darmi qualche idea? Grazie mille!

risposta

5

Un operatore ternario "vero" come _ ? _ : _ richiede il supporto della lingua. Swift consente di creare e personalizzare solo operatori unari e binari.

È possibile utilizzare la tecnica nella risposta di @ NateCook per creare una coppia di operatori binari che insieme funzionano come un operatore ternario, ma sono ancora operatori binari indipendenti: è possibile utilizzarli singolarmente. (Al contrario, _ ? _ : _ è solo un operatore ternario,. _ ? _ e _ : _ non possono essere utilizzati singolarmente)

Naturalmente, perché fermarsi qui? È possibile collegare più operatori binari per creare operatori quaternari e così via. Per il credito in più, provare a fare voi stessi un operatore nave spaziale estesa:

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

(... ma vi prego di fare questo solo come un esercizio accademico, o chiunque altro che lavora con il codice che si scrive vi odierà.)

18

È in grado di farlo dichiarando due operatori separati che lavorano insieme e utilizzano una funzione al curry per uno degli operatori.

Dichiariamo un operatore ternario x +- y +|- z che controllerà il segno del valore iniziale x, e quindi restituire il secondo valore y se il segno è zero o positivo e il valore finale z se il segno è negativo. Cioè dovremmo essere in grado di scrivere:

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

Inizieremo dichiarando i due operatori. La parte importante è avere la precedenza più alta al secondo gestore - noi valuteremo quella parte prima e torniamo una funzione:

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

quindi definire le funzioni - definiremo il secondo prima:

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

La parte importante qui è che questa funzione è al limite: se la chiami solo con i primi due parametri, invece di restituire un valore T, restituisce una funzione (left: Bool) -> T. Che diventa il secondo parametro della funzione per il nostro primo operatore:

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

E ora possiamo usare il nostro operatore "ternario", in questo modo:

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

Nota: ho scritto a blog post on this subject con un altro esempio.

+1

'func + | -' probabilmente dovrebbe usare anche le autoclosures, in modo che i parametri vengano valutati pigramente, come nel solito'?: '. Inoltre, mentre questo crea qualcosa che funziona come un operatore ternario, non si può effettivamente usare '?' E ':' poiché nessuno di questi è un token 'operator' valido in swift. – bames53

+0

Stavo tornando per fare quella modifica! E sì, '?:' Stesso non può essere ignorato. –

+0

Esempio simile qui: http://www.reddit.com/r/swift/comments/2fjwav/custom_ternary_operator/ –