2014-10-03 3 views
22

Questo è un codice valido Swift:Swift nil ha un valore numerico?

println(nil < 1) 

E l'uscita sarà vero, allo stesso modo

println(nil > 1) 

sarà falsa (il numero 1 è arbitrario, si può fare lo stesso per -1 e probabilmente qualcos'altro). Il motivo per cui lo chiedo è perché ho visto un codice che ha provato a confrontare "some_string".toInt() con un valore numerico e lo ha compilato, il che sembra sbagliato considerando toInt() restituisce Int?.

La mia domanda è, dovrebbe essere sintassi valida in Swift? In tal caso, qual è il valore numerico di nil?


Swift 3.0 Update:

Sembra Swift Evolution affrontato questo problema removing the optional comparison operators. Questo non è più un problema in Swift 3.0 in quanto non viene compilato.

+2

questo mi sembra un insetto. –

+0

'Int.min as Int? > nil' '$ R14: Bool = true', forse è inteso per consentire il confronto di due' Int? 'e' Int.min> nil' fornisce l'errore di compilazione –

+0

@BryanChen È sicuramente interessante. Direi sicuramente un bug in questo contesto, ma mi piacerebbe davvero sapere come sta arrivando a questa conclusione. –

risposta

17

Credo che quello che sta accadendo sia che il valore letterale 1 venga implicitamente tipizzato al tipo Int? dal confronto a nil. Per quelli che non sono abituati a Swift, spiegherò un po 'oltre. Swift ha un concetto chiamato "optionals", che può avere un valore o essere nil. (Per chiunque abbia familiarità con Haskell, questa è fondamentalmente la monade Maybe). È illegale assegnare nil a una variabile che non è stata definita esplicitamente come facoltativa, pertanto let i: Int = nil verrà rifiutata dal compilatore. Ciò consente numerosi vantaggi che sono fuori dallo scopo di questa risposta ed è un modo piuttosto intelligente per farlo.

Quello che sta succedendo qui, però, è che la letterale 1 è un valore valido di diversi tipi: Int, Int32, Int64, UInt32, UInt64, ecc, ecc, ecc Ed è anche un valore valido di le versioni opzionali di quei tipi: Int?, Int32?, ecc

Così, quando il compilatore Swift vede un confronto tra un valore letterale e nil, si cerca di trovare un tipo che entrambi questi valori sarebbero validi per. 1 è un valore valido del tipo Int? e nil è anche un valore valido del tipo Int?, quindi applica l'operatore di confronto con la firma del tipo (Int?, Int?) -> Bool. (Questo è l'operatore di confronto che prende due valori Int? e restituisce uno Bool). Le regole di quell'operatore dicono che i valori nil ordinano più in basso di qualsiasi altra cosa, anche Int.min, e quindi ottieni il risultato visualizzato nella domanda dell'OP.

+1

Per inciso, questo non sarebbe possibile in Haskell (a quanto ho capito), perché il monade 'Maybe' è definito come avente due possibili valori: o' Nothing' o 'Just x' (dove' x' può essere di qualsiasi genere). E poiché 'x' non può mai essere implicitamente promosso a' Just x', il compilatore Haskell, dato un operatore di confronto che confronta i tipi 'Maybe Int' e' Maybe Int', proibisce qualsiasi confronto tra '1' e' Nothing' , perché il primo è di tipo 'Int 'e non esiste un operatore per confrontare' Int' e 'Maybe Int'. (Ma confrontare 'Just 1' e' Nothing' sarebbe valido: entrambi sono di tipo 'Maybe Int'). – rmunn

+0

Correzione alla parentetica nel mio commento precedente: 'Nothing' è di valore' Forse x', dove 'x' può essere di qualsiasi tipo. Ma ciò corrisponde al tipo "Forse Int", quindi il confronto sarebbe valido. – rmunn

+7

Una delle firme dell'operatore '<' è: 'func << T: _Comparable> (lhs: T ?, rhs: T?) -> Bool'; Credo che sia da dove viene questo. Scrivere una funzione di test rapido: 'func test (lhs: T ?, rhs: T?)' E chiama 'test (nil, 1)' funziona. Chiamando 'println (_stdlib_getDemangledTypeName (rhs))' all'interno di quella funzione stampa 'Swift.Optional'; chiamando 'println (_stdlib_getDemangledTypeName (rhs!))' stampa 'Swift.Int'. Quindi, 'rhs', che è stato passato come' 1' nella chiamata è un 'Int?'. –