2016-04-08 6 views
6

Ich versuche, BooleanLiteralConvertible Unterstützung meiner Klasse hinzuzufügen, so dass ich es mit einem boolean instanziieren kann. Die Sache, die mich für eine Schleife wirft, ist die Unterscheidung zwischen einem booleschen Wert und einem booleschen Literal.Warum benötigt Swift BooleanLiteralConvertible ein boolesches Literal?

Zum Beispiel, nach dem Protokoll hinzugefügt ich versuchte, dies:

func setSelected(value: Bool) { 
    var node: MyClass = value 
} 

Aber Swift darüber beschwert, dass es nicht Bool-MyClass umwandeln kann. Es dauerte eine Weile, bis ich erkannte, dass es sich um einen booleschen Literal handeln musste. Seltsamerweise funktioniert das Folgende gut:

func setSelected(value: Bool) { 
    var node: MyClass = value ? true : false 
} 

... was für mich absolut albern scheint. Gibt es einen berechtigten Grund für diese scheinbar sehr bizarre Anforderung?

+0

Haben Sie 'value!' Versucht? – mattsven

+0

"Wert" ist bereits ein nicht-optionaler 'Bool', ich kann kein'! 'Darauf anwenden. – devios1

Antwort

2

ich die Frage gerne schreiben. Nur das Swift - Team konnte definitiv antworten, aber ich kann darüber spekulieren, warum: die Umwandlung eines typisierten Wertes in eine Variable eines anderen Typs ohne eine explizite Konvertierung oder Umwandlung ist sehr leicht mit einem Programmierfehler zu verwechseln, und in vielen Fällen ist das etwas Compiler sollte darüber warnen.

Beispiel (und davon ausgehen, dass Person ist auch ein StringLiteralConvertible, die als wörtlichen als auch mit einer String-Variablen initialisiert werden können, wie Sie in Ihrer Frage stellen):

struct Person { 

    private static var idCounter = 1 

    var name:String 
    let id:Int 

    init(withName name:String) { 
     Person.idCounter += 1 
     self.name = name 
     self.id = Person.idCounter 
    } 
} 

var person = Person(withName:"Mary") 
let name = "John" 
person = name 

Der obige Code sieht verdächtig nach einem Fehler , wobei der Programmierer einer Variablen vom Typ Person einen Wert vom falschen Typ (String) zuweist. Es kann tatsächlich ein Fehler sein. Vielleicht wollte der Programmierer nur den Namen der Person (person.name = name) ändern, ohne eine neue Person mit einer neuen eindeutigen ID zu erstellen. Oder vielleicht wollte der Programmierer einen anderen Wert zu person zuweisen, aber einen Tippfehler oder Code-Vervollständigungsfehler gemacht. Schwer zu sagen, ohne entweder der ursprüngliche Programmierer zu sein, oder sorgfältig den ganzen Kontext zu studieren, um zu sehen, ob diese Umwandlung Sinn macht. Und es wird schwieriger, je weiter die Zuweisung von der Stelle entfernt wird, an der die Variablen ursprünglich initialisiert wurden. Warnt der Compiler hier, dass ein Wert vom Typ String einer Variablen vom Typ Person zugewiesen wird?

Das Beispiel würde so weit mehr klar, und mehr im Einklang mit Swift-Konventionen sein:

var person = Person(withName:"Mary") 
let name = "John" 
person = Person(withName:name) 

Die obige Version ist völlig eindeutig, sowohl an die Compiler und an anderen Programmierern, die diese später zu lesen.

+0

Nun, es ist eindeutig subjektiv an einem Punkt. Ich meine, warum brauchen wir überhaupt literale Convertibles, wenn Sie sich Sorgen um die Lesbarkeit des Codes machen? 'person =" Bob "' zu mir fühlt sich genau so "falsch" wie 'person = name', aber wenn du es erlaubst, warum nicht auch das andere? Persönlich wollte ich diese Funktion verwenden, um meine Syntax übersichtlicher und einfacher zu schreiben. Ständig einen Initialisierer aufrufen zu müssen, fühlt sich einfach an, als wäre er mit einer impliziten Konvertierung zu vermeiden. Es ist immer noch statisch gültig und kompilierungssicher, auch wenn es nicht bekannt aussieht. – devios1

+0

Durch die Einführung dieser Einschränkung erzeugt die Sprache tatsächlich einen sehr starken semantischen Unterschied zwischen der Verwendung eines Literalwerts und der Verwendung einer Variablen des gleichen Typs, wobei diese in den meisten Sprachen auf fundamentaler Ebene vollständig austauschbar sind . Für mich fühlt sich das sehr nach einem Schritt in die falsche Richtung an, wodurch ein verzweigter Punkt im konzeptionellen Verständnis von Werten und Typen entsteht und die Sprache unnötig kompliziert wird. – devios1

+0

@devios Ich denke du bringst gute Punkte. Es gibt keinen großen Unterschied zwischen einer Literalnotation und einem tatsächlichen typisierten Wert, aber es gibt ein Paar, das ich mir vorstellen kann: 1) Literalnotationskräfte, die den Wert an der Initialisierungsstelle spezifizieren, z. 'let thing =" Foo "' anstatt "let thing = someStringValueWeDontKnow", was Literale etwas weniger mehrdeutig und fehleranfällig macht –

6

konforme Typen zu BooleanLiteralConvertible kann mit den Booleschen Literaletrue und false, z.B. initialisiert werden

let mc : MyClass = true 

Das hat nichts mit der Initialisierung des Typs mit einem Booleschen Wert zu tun:

let value : Bool = // ... some boolean value 
let mc : MyClass = value // error: cannot convert value of type 'Bool' to specified type 'MyClass' 

und es ist - soweit ich weiß - keine Möglichkeit, eine solche implizite Umbauarbeiten zu machen . Sie würden eine benutzerdefinierte Methode init

init(bool : Bool) { 
    // ... 
} 

und initialisieren das Objekt als

let value : Bool = // ... some boolean value 
let mc = MyClass(bool: value) 
+0

Ein weiteres Beispiel für Swifts bipolare Störung, imo. ;) Manchmal verleiht Swift's Power einer sehr prägnanten und eleganten Syntax. Zu anderen Zeiten bringt es dich dazu, Dinge zu tun, die einen Amateur zum Weinen bringen. – devios1

+1

@devios: In frühen Swift-Versionen konnten Sie implizite Konvertierungsmethoden von beliebigen Typen in Ihren Typ implementieren. Dieses Feature wurde später entfernt, aber ich erinnere mich nicht an die Begründung. –

Verwandte Themen