So lief ich in this code snippet, die zeigt, wie man "unbewegliche" Typen in Rust erstellt - Bewegungen werden verhindert, weil der Compiler das Objekt für seine gesamte Lebensdauer als geliehen behandelt.Warum wird eine Zelle zum Erstellen unbeweglicher Objekte verwendet?
use std::cell::Cell;
use std::marker;
struct Unmovable<'a> {
lock: Cell<marker::ContravariantLifetime<'a>>,
marker: marker::NoCopy
}
impl<'a> Unmovable<'a> {
fn new() -> Unmovable<'a> {
Unmovable {
lock: Cell::new(marker::ContravariantLifetime),
marker: marker::NoCopy
}
}
fn lock(&'a self) {
self.lock.set(marker::ContravariantLifetime);
}
fn new_in(self_: &'a mut Option<Unmovable<'a>>) {
*self_ = Some(Unmovable::new());
self_.as_ref().unwrap().lock();
}
}
fn main(){
let x = Unmovable::new();
x.lock();
// error: cannot move out of `x` because it is borrowed
// let z = x;
let mut y = None;
Unmovable::new_in(&mut y);
// error: cannot move out of `y` because it is borrowed
// let z = y;
assert_eq!(std::mem::size_of::<Unmovable>(), 0)
}
Ich verstehe noch nicht, wie das funktioniert. Meine Vermutung ist, dass die Lebensdauer des borrow-pointer-Arguments gezwungen ist, die Lebensdauer des Lock-Feldes zu erreichen. Das Seltsame ist, dieser Code weiterhin in der gleichen Art und Weise arbeiten, wenn:
- ich
ContravariantLifetime<'a>
-CovariantLifetime<'a>
ändern oder zuInvariantLifetime<'a>
. - Ich entferne den Körper der
lock
Methode.
Aber, wenn ich die Cell
, entfernen und lock: marker::ContravariantLifetime<'a>
nur direkt verwenden, da so:
use std::marker;
struct Unmovable<'a> {
lock: marker::ContravariantLifetime<'a>,
marker: marker::NoCopy
}
impl<'a> Unmovable<'a> {
fn new() -> Unmovable<'a> {
Unmovable {
lock: marker::ContravariantLifetime,
marker: marker::NoCopy
}
}
fn lock(&'a self) {
}
fn new_in(self_: &'a mut Option<Unmovable<'a>>) {
*self_ = Some(Unmovable::new());
self_.as_ref().unwrap().lock();
}
}
fn main(){
let x = Unmovable::new();
x.lock();
// does not error?
let z = x;
let mut y = None;
Unmovable::new_in(&mut y);
// does not error?
let z = y;
assert_eq!(std::mem::size_of::<Unmovable>(), 0)
}
Dann wird das "unverrückbar" Objekt bewegen darf. Warum sollte das sein?
Beantwortete alle meine Fragen! Außer dem, der nicht zu beantworten ist (warum kannst du dich mit * entweder * CovariantLifetime * oder ContravariantLifetime bewegen?), Was wie ein weiterer möglicher Compiler-Fehler aussieht. Vielen Dank! –
Die angegebene Invarianz von '&' a mut T 'ist falsch: sie ist invariant gegenüber 'T' und kontravariant in Bezug auf''a. Es ist zulässig, ein '& 'ein mut T' zu einem '&' kleines mut T 'zu zwingen. – huon
Auch "InvarianceLifetime" ist die Schnittmenge von 'ContravarianceLifetime' und' CovarianceLifetime', also verhält es sich in Bezug auf Einschränkungen wie beides. Jeder der Markierungstypen stellt tatsächlich das Entfernen der Funktionalität dar, anstatt sie hinzuzufügen: "Contra ..." ist nur * nicht * kovariant, "Co ..." ist einfach nicht kontravariant, und "In ..." ist weder kovariant noch kontravariant. – huon