2016-05-28 16 views
1

Ich habe den folgenden Code in D:Wie kann ich unveränderliche Referenztypen ohne Break Constance zurückgeben?

import std.stdio; 
import std.container.array; 

class RefType { } 

class MyContainer { 
    private Array!RefType test; 
    RefType result() const { // I want const on this, not on return type 
     return test[0];  // use opIndex() from Array(T) 
     // Error: cannot implicitly convert expression (this.test.opIndex(0u)) 
     // of type const(RefType) to main.RefType 
    } 
} 

int main(string[] argv) { 
    auto c = new MyContainer; auto r = c.result(); return 0; 
} 

Wie man sehen kann ich einen Referenztyp aus einer benutzerdefinierten Containerklasse zurückkehren möchten. Aber der opIndex() von Array gibt nicht die Erlaubnis, das zu tun, warum?

Ich denke, dass opIndex() eine RefType anstelle eines const(RefType) Wert zurückgeben sollte, weil das Array Array!RefType ist.

Ist das ein Fehler? oder ist die Designabsicht? Wenn dies das geplante Design ist, wie bekomme ich das, was ich will?

+0

versuchen, ersetzen Sie Ihre 'const' mit' inout'.so 'inout (RefType) result() inout {Rückgabetest [0]; } 'und sehen, ob das für Sie funktioniert –

+0

Ja, das funktioniert! Aber was bedeutet das Inout-Schlüsselwort? –

+0

Ich habe getestet und nicht bricht die constness :) Bitte füllen Sie es als Antwort. Es ist nur ich fand. –

Antwort

0

Ich denke, dass opIndex() eine RefType zurückgeben sollte anstelle eines const (RefType) Wert, weil das Array Array ist! RefType.

Nein, das ist falsch. Wenn Sie Ihre Methode als const definieren, haben Sie auch angegeben, dass alle Mitglieder der Klasse auch const sind. Dies bedeutet, dass unabhängig von dem Typ, den das Mitglied in der Definition hat, innerhalb Ihrer result Methode (mindestens) const sind. Daher ist der Compiler vollständig berechtigt, den zurückgegebenen Fehler zurückzugeben.

Der üblicher (zB C++) Weg, dies zu lösen, ist zwei zu definieren (oder, in D, drei) Überlastungen:

RefType result() { 
    return test[0]; 
} 
RefType result() const { 
    return test[0]; 
} 
RefType result() immutable { 
    return test[0]; 
} 

So, ein für den Fall der Klasse wandelbar ist, das ein veränderbares zurück Referenz. Eine für den Fall, dass die Klasse const ist, die eine Konstante const zurückgibt, und eine für den Fall, dass die Klasse unveränderlich ist, was eine unveränderliche Referenz zurückgibt.

Sie werden jedoch bemerken, dass abgesehen von der Methode Dekoration, alle drei Implementierungen genau gleich sind. Um zu verhindern, dass Sie drei identische Implementierungen definiert, hat D den inout Modifikator:

RefType result() inout { 
    return test[0]; 
} 

Diese einheitliche Definition ersetzt alle drei der oben genannten Definitionen. Als Faustregel schreiben Sie einfach Ihre Definition wie gewohnt, aber platzieren Sie inout an einem beliebigen Platz, an dem Sie sonst const platzieren würden.

+0

Ok, dann hatte ich gestern eine Verwirrung. Ich möchte, dass meine Containerklasse nicht geändert werden kann, aber ich möchte nicht verhindern, dass die Benutzer die Objekte ändern, die der Container enthält. Dann sind in diesem Fall weder const noch unveränderlich nützlich. Recht? –

+0

@JairoAndresVelascoRomero Ja, weil "const" und "immutable" in D transitiv sind, gilt keiner von beiden für Ihren Anwendungsfall. Sie müssen die Unveränderbarkeit der Sammlung selbst auf API-Ebene erzwingen. –

+0

Wenn Sie den RefType zurückgeben, muss er wahrscheinlich auch wegen der transitiven const-Regeln "inout" sein - innerhalb der const/immutable/inout-Methode ist alles, was sie durch "this" erreichen, vom gleichen Typ (oder stärker). Tut mir leid, dass ich es nicht selbst geschrieben habe, war ein arbeitsreiches Wochenende. Aber mit dieser kleinen Nisse sollte diese Antwort gut sein. –

1

Ich denke, dass opIndex() eine RefType zurückgeben sollte anstelle eines const (RefType) Wert, weil das Array Array ist! RefType.

Diese Annahme ist falsch. Da Ihre OpIndex-Methode als const. Die implizit gegebene Referenz ist auch const (is (this == const (MyContainer)). Das bedeutet, dass alles, auf das Sie zugreifen, auch const ist, da D's const transitiv ist.Wenn Sie in Ihrer const-Methode auf etwas const zugreifen, werden Sie get etwas const. Rückgabe von etwas nicht-const von dieser Methode ist in D (zum Glück) illegal. Die einzigen Dinge nicht-const, die von einer const-Methode zurückgegeben werden können, sind Werttypen ohne Indirection.

Eine gültige, um Sie eingeben arbeiten als nicht-const, const und unveränderlich können Sie schreiben:

inout(RefType) result() inout { ... } 
+0

Ja, das ist der Weg zu gehen. – DejanLekic