Как работают пожизненные ограничения на структуры в Rust?

Вчера в IRC обсуждался этот вопрос, и я чувствовал смутное недовольство.

Вопрос был:

Как вы определяете время жизни структуры, чтобы ограничить ее содержимое только теми вещами, которые живут так же долго, как и "себя".

то есть "сам" такого рода вещи.

Моя первая реакция была: ты не можешь.

Если вы создаете структуру Foo<'a>, время жизни, связанное с ней, определяется из ссылок, которые она содержит; если структура не содержит ссылку на себя (это невозможно), у вас не может быть такого "собственного времени жизни".

Об этом было много болтовни, и в итоге я написал этот манеж:

#[deriving(Show)]
struct Bar;

#[deriving(Show)]
struct Foo<'a> {
  a:&'a Bar,
  b:&'a Bar
}

fn factory<'a>(v1:&'a Bar, v2: &'a Bar) -> Foo<'a> {
  return Foo {
    a: v1,
    b: v2
  };
}

fn main() { // <---- Let's call this block lifetime 'one
  let a = Bar; 
  let c = &a; // <-- C has lifetime 'one
  { // <------------ Let's call this block lifetime 'two
    let b = Bar;

    let mut foo1 = factory(c, c);  
    foo1.b = &b;

    let mut foo2 = factory(&b, &b);  
    foo2.a = &a;

    println!("{}", foo1);
    println!("{}", foo2);
  }
}

Тем не менее, я сейчас больше сбит с толку, чем меньше.

Итак, в строгом смысле в вышесказанном:

  • с "один"
  • и б имеет два
  • 'static>' one> 'two (то есть' two ограничено 'one).
  • у foo1 есть один
  • у foo2 есть два

Теперь моя путаница:

Foo<'a> указывает, что' a - это минимальная граница времени жизни, которая может содержаться в экземпляре Foo.

  • Поскольку 'one>' two, foo2 должен содержать a &'one a; это работает.

  • Поскольку 'two>' one, foo1 не должен содержать &'two b; Однако это работает.

Зачем?

Похоже, моя путаница возникает из-за одного из двух заблуждений; или:

1) Экземпляр foo1 находится на лице Foo<'two>, а не Foo<' one>.

Я не понимаю, почему это так, поскольку он изготовлен на фабрике<'a>, где <' a> - время жизни c; что "один, а не" два. Нет абсолютно никакого способа, которым c может быть &'два в примере выше. Время жизни 'два недоступно на фабрике функций, где создается Foo.

2) Структурные жизни не работают так, как я понимаю, как они работают; то есть. время жизни 'a на экземпляре Foo может как-то меняться после создания экземпляра (например, на ходу?)

... но я не знаю какой.

1 ответ

Решение

Параметры времени жизни на ссылках противоречивы: при необходимости их можно заменить более коротким сроком службы.

По сути, вы ошиблись. Когда у вас есть &'one Barвы не можете назначить ссылку на значение с более коротким временем жизни (например, 'two здесь), в противном случае ссылка будет зависать, когда выполнение покидает 'two объем. Тем не менее, когда у вас есть &'two Barможно назначить ссылку на значение с более длительным сроком службы (например, 'one а также 'static), потому что ссылка выйдет из области видимости раньше, чем референт.

Почему ваша программа компилируется? Компилятор не только использует информацию из обращений к factory выбрать подходящий срок жизни; он также использует информацию из заданий. &a имеет тип &'one Bar а также &b имеет тип &'two Bar, Так как 'two начинается после 'one и заканчивается раньше 'oneкомпилятор может вызвать &'one Bar к &'two Bar, В объектно-ориентированных терминах &'one Bar это &'two Bar (&'one Bar это подтип &'two Bar). Так же, как в Java, вы можете передать String в качестве аргумента функции, которая ожидает Object, Просто отношение подтипов - это обратный путь на всю жизнь.

Это означает, что мы нашли общий тип для &a а также &b: &'two Bar, Таким образом, компилятор выводит 'two за 'a в звонках factory,

Обратите внимание, что тип foo2 не изменяется при назначении; тип значения всегда статический.

Другие вопросы по тегам