Почему я не могу вызвать метод с временным значением?

Основная проблема заключается в том, что вы пытаетесь импортировать класс, но используете синтаксис, который работает только для импорта модуля. В частности, import lib.A никогда не будет работать, если A - это класс, определенный в модуле lib.a (и импортированный в пространство имен верхнего уровня lib).

Я предлагаю, чтобы вы избегаете использования синтаксиса from _ import _, если вам это действительно не нужно. Это облегчает решение зависимостей:

lib/a.py:

import lib.b # note, we're not importing the class B, just the module b!

class A():
    def foo(self):
        return lib.b.B() # use the class later, with a qualified name

lib/b.py:

import lib.a # again, just import the module, not the class

class B():
    def foo(self):
        return lib.a.A() # use another qualified name reference

lib/__init__.py:

from a import A # these imports are fine, since the sub-modules don't rely on them
from b import B # they can be the public API for the A and B classes

Вы также можете использовать относительный импорт модулей, если вы не хотите, чтобы a и b зависели от имени своего пакета lib.

Это обязательно работать, потому что ни один из классов A или B на самом деле не требует, чтобы другой существовал еще, чтобы быть определенным. Только после того, как они импортируются, экземпляры A должны знать о классе B (и наоборот).

Если один из классов, унаследованный от другого или иным образом используемый экземпляр другого в верхний уровень, вам нужно быть более осторожным, какой модуль был загружен первым, или он может все еще сломаться.

1
задан Shepmaster 17 January 2019 в 15:31
поделиться

2 ответа

Foo::new(words).split_first() будет интерпретироваться примерно как

let tmp = Foo::new(words);
let ret = tmp.split_first();
drop(tmp);
ret

Если бы Rust позволил вам сделать это, ссылки в ret указали бы [править: разрешено типом split_first указывать *] на теперь упавшее значение tmp. Так что хорошо, что Руст запрещает это. Если бы вы написали эквивалентную однострочную версию в C ++, вы бы молча получили неопределенное поведение.

Написав let привязку самостоятельно, вы задерживаете отбрасывание до конца области действия, расширяя тем самым область, где эти ссылки безопасны.

Подробнее см. временные времена жизни в справочнике по ржавчине.

* Редактировать: Как указал Jmb , реальная проблема в этом конкретном примере заключается в том, что тип

fn split_first(&'a self) -> &'a str

недостаточно конкретен, и лучшим решением является уточните тип до:

fn split_first<'b>(&'b self) -> &'a str

, что может быть сокращено:

fn split_first(&self) -> &'a str

Это передает предполагаемую гарантию того, что возвращаемые ссылки не указывают на Foo<'a> (только на строку сам по себе).

0
ответ дан Anders Kaseorg 17 January 2019 в 15:31
поделиться

Краткий ответ: удалить время жизни 'a для параметра self параметра split_first: fn split_first(&self) -> &'a str ( детская площадка ).

Длинный ответ:

Когда вы пишете этот код:

struct Foo<'a> {
    part: &'a str,
}

impl<'a> Foo<'a> {
    fn new(s: &'a str) -> Self {
        Foo { part: s }
    }
}

Вы говорите компилятору, что все Foo экземпляры связаны с некоторым временем жизни [ 118], которое должно быть равно или короче времени жизни строки, передаваемой в качестве параметра в Foo::new. Это время жизни 'a может отличаться от времени жизни каждого экземпляра Foo. Затем вы пишете:

let words = "Sometimes think, the greatest sorrow than older";
Foo::new(words)

Компилятор делает вывод, что время жизни 'a должно быть равно или короче времени жизни words. Запретив любые другие ограничения, компилятор будет использовать время жизни words, которое равно 'static, поэтому оно действует в течение всего срока службы программы.

Когда вы добавляете определение split_first:

fn split_first(&'a self) -> &'a str

Вы добавляете дополнительное ограничение: вы говорите, что 'a также должно быть равно или короче времени жизни self , Поэтому компилятор будет принимать меньшее время жизни words и время жизни временного экземпляра Foo, то есть время жизни временного экземпляра. @ Ответ AndersKaseorg объясняет, почему это не работает.

Удаляя время жизни 'a для параметра self, я декоррелирую 'a из времени жизни временного, поэтому компилятор может снова сделать вывод, что 'a - это время жизни words, которое достаточно долго для работы программы.

0
ответ дан Shepmaster 17 January 2019 в 15:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: