diesen Code Gegeben:Warum unterstützt Rust nicht das Trait-Objekt-Upcasting?
trait Base {
fn a(&self);
fn b(&self);
fn c(&self);
fn d(&self);
}
trait Derived : Base {
fn e(&self);
fn f(&self);
fn g(&self);
}
struct S;
impl Derived for S {
fn e(&self) {}
fn f(&self) {}
fn g(&self) {}
}
impl Base for S {
fn a(&self) {}
fn b(&self) {}
fn c(&self) {}
fn d(&self) {}
}
Leider habe ich nicht &Derived
-&Base
werfen können. Ich fragte mich, warum war das, weil die Derived
vtable auf die eine oder andere Weise auf Base
Methoden verweisen muss. die folgende
Nun, enthüllt die LLVM IR Inspektion:
@vtable4 = internal unnamed_addr constant {
void (i8*)*,
i64,
i64,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*
} {
void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE,
i64 0,
i64 1,
void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE,
void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE,
void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE,
void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE
}
@vtable26 = internal unnamed_addr constant {
void (i8*)*,
i64,
i64,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*,
void (%struct.S*)*
} {
void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE,
i64 0,
i64 1,
void (%struct.S*)* @_ZN9S.Derived1e20h9992ddd0854253d1WaaE,
void (%struct.S*)* @_ZN9S.Derived1f20h849d0c78b0615f092aaE,
void (%struct.S*)* @_ZN9S.Derived1g20hae95d0f1a38ed23b8aaE,
void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE,
void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE,
void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE,
void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE
}
Alle Rust vtables enthalten Zeiger auf destructor, Größe und Ausrichtung in den ersten Feldern und subtrait vtables sie nicht duplizieren, wenn supertrait Methoden verweisen, Verwenden Sie auch keinen indirekten Verweis auf Supertrait-Vtables. Sie haben nur Kopien der Methodenzeiger wörtlich und nichts anderes.
dass Design Gegeben, es ist leicht zu verstehen, warum dies nicht funktioniert. Eine neue vtable müsste in Laufzeit erstellt werden, die wahrscheinlich auf dem Stapel liegen würde, und das ist nicht gerade eine elegante (oder optimale) Lösung.
Es gibt natürlich einige Problemumgehungen wie das Hinzufügen expliziter Upcast-Methoden zur Schnittstelle, aber das erfordert ziemlich viel Boilerplate (oder Makro-Raserei), um richtig zu funktionieren.
Nun, die Frage ist - warum es nicht in irgendeiner Weise implementiert, das Merkmal Objekt Upcasting ermöglichen würde? Wie z. B. Hinzufügen eines Zeigers zur V-Tabelle des Supertraits in der Vtable des Subtrahts. Fürs Erste scheint Rust's dynamischer Versand die LSP, die ein sehr grundlegendes Prinzip für objektorientiertes Design ist, nicht zu erfüllen.
Natürlich können Sie statische Versand verwenden, die in Rust in der Tat sehr elegant ist, aber es führt leicht zu Code Bloat, die manchmal wichtiger ist als Rechenleistung - wie auf eingebetteten Systemen, und Rust-Entwickler behaupten, solche zu unterstützen Anwendungsfälle der Sprache. In vielen Fällen können Sie auch erfolgreich ein Modell verwenden, das kein reines OO ist, das durch das funktionale Design von Rust unterstützt zu werden scheint. Trotzdem unterstützt Rust viele der nützlichen OO-Muster ... also warum nicht der LSP?
Kennt jemand die Gründe für eine solche Konstruktion?
Als Randnotiz: Rust ist keine objektorientierte Sprache. Eigenschaften sind keine Schnittstellen, sie sind mehr wie Typklassen von Haskell. Rust hat auch keine Subtypisierung, daher ist LSP etwas unbrauchbar, weil seine Definition an die Subtyping-Beziehung gebunden ist. –
Wie ich bereits sagte, unterstützt Rust viele OO-artige Abstraktionen, und Eigenschaften dürfen erben und bilden so etwas wie eine Typhierarchie. Für mich wäre es natürlich, LSP für Merkmalsobjekte zu unterstützen, auch wenn OO nicht das Hauptparadigma der Sprache ist. – kFYatek
Bitte stellen Sie sicher, nützliche Antworten zu verbessern und markieren Sie eine Antwort als akzeptiert, wenn es Ihr Problem gelöst hat! Wenn keine Antwort akzeptabel ist, ziehen Sie in Erwägung, Kommentare zu hinterlassen, die den Grund erklären, oder bearbeiten Sie Ihre Frage, um das Problem anders zu formulieren. – Shepmaster