2017-11-28 4 views
2

Ich implementiere ein Redux-Geschäft, wo ich das Geschäft als unveränderlich behandeln. Daher sieht das Geschäft in etwa so aus:Wie erkennt man, ob ein optionaler benannter Parameter in Dart angegeben wurde?

class State { 
    final String firstname; 
    final String lastname; 

    State(this.firstname, this.lastname); 

    State.initial() 
     : this.firstname = null, 
     this.lastname = null; 

    State copy({String firstname, String lastname}) => 
    new State(firstname ?? this.firstname, lastname ?? this.lastname); 
} 

Das alles funktioniert gut und ich kann den Status kopieren und einzelne Felder innerhalb der Kopie ersetzen.

state.copy(firstname: "foo"); 

aber jetzt kann ich ein Feld natürlich nicht auf null zurücksetzen.

state.copy(firstname: null); 

funktioniert nicht.

Ich habe auch versucht, so etwas wie:

State copy({String firstname = this.firstname, String lastname = this.lastname}) => ... 

aber Dart nicht nicht const als Standardwerte ermöglichen.

Antwort

3

Sie können eine spezielle Markierung in der Datei verwenden, wie diese

const _noValueGiven = const Object(); 

class State { 
    ... 
    State copy({String firstName: _noValueGiven, String lastName: _noValueGiven}) { 
    if (identical(firstName, _noValueGiven)) { 
     firstName = this.firstName; 
    } 
    ... 
    } 
} 
+1

Beachten Sie, dass dies in Dart 2.0 (Zuweisung von Object zu String) nicht zulässig ist. Sie könnten eine Sentinel-Zeichenfolge verwenden, d. H. "__notSpecified__" – matanlurey

+0

Außerdem ist 'const Object()' ein unsicherer Sentinel-Wert, weil Konstanten kanonisiert sind. Jedes andere 'const Object() 'im Programm wird zum selben Objekt ausgewertet. – lrn

+0

Bisher ging ich mit dieser Lösung und es sieht gut aus und hat nicht viel Aufwand Overhead. Und ich verwende es nicht für String-Parameter, sondern für Objekte. Für Strings würde ich mit "" für Einstellung auf leer und null für nicht vorhanden gehen.Ich bin mir über die Kanonisierung nicht so sicher, ich denke, ich muss mehr damit spielen, um diese Implikation zu verstehen. – Fabian

1

Es gibt keine Möglichkeit, zu unterscheiden, ob ein Parameter nicht an der Aufrufstelle zur Verfügung gestellt wurde, oder es wurde mit dem gleichen Wert wie der Standard bereitgestellt Wert.

Sie haben einen Wert auszuwählen, die tatsächlich als Argument zur Verfügung gestellt wird unwahrscheinlich ist, in diesem Fall vielleicht die leere Zeichenkette "" (Sie, dass eine leere Zeichenfolge nicht ein gültiger Name ist sagen kann, so bieten sie ignoriert , während die Übergabe in null eine Möglichkeit ist, den Namen zu löschen).

Wenn es keinen Wert gibt, der nicht aussagekräftig ist, müssen Sie einen Sentinel eines anderen Typs verwenden und die Funktion diesen Typ akzeptieren, vorzugsweise ohne den Typ- oder Sentinel-Wert in die API-Dokumentation eindringen zu lassen.

, das zu tun, Sie eine private Unterklasse verwenden, um die Implementierung zu verbergen:

abstract class State { 
    ... 
    State(String firstName, String lastName) = _State; 
    State copy({String firstName, String lastName}); 
} 
class _State implements State { 
    String firstName, lastName; 
    _State(this.firstName, this.lastName); 
    State copy({Object firstName = 0, Object lastName = 0}) { 
    if (firstName != null && firstName is! String) { 
     firstName = this.firstName; 
    } 
    if (lastName != null && lastName is! String) { 
     lastName = this.lastName; 
    } 
    return new _State(firstName, lastName); 
    } 
} 

Auf diese Weise hat kein Benutzer die Art, die nicht-String-Argument erlaubt, so dass sie erhalten Warnungen, wenn sie versuchen Sie, und Ihr _State.copy Code ist sicher für jedes tatsächliche Argument - es ignoriert alle nicht-String, nicht null Wert.

Wenn möglich, ich empfehle wirklich, null bedeuten dasselbe wie das Argument zu verzichten. Es macht es für alle anderen viel einfacher, einen Anruf an die Methode weiterzuleiten. Ansonsten müssen sie auch erkennen, ob ihre Parameter bestanden wurden oder nicht. In diesem Fall würde ich wahrscheinlich die leere Zeichenfolge verwenden, um leere Werte anstelle von null darzustellen und null den Marker "no argument passed" zu lassen.

Verwandte Themen