2015-12-19 5 views
2

Я снова сражаюсь с жизнями. Или на самом деле, я как бы выиграл бой, но я не уверен, что результат - это намеченный способ справиться с этим.Есть ли способ опустить жизни для этой черты здесь?

Скажем, у меня есть структура с двумя сроками службы: Inner<'a, 'b>. Теперь я хочу написать черту, которая определяет метод new(inner: &Inner) -> Self. Разработчик должен иметь возможность свободно хранить ссылку на Inner и определять другие методы работы с ней.

Я пришел с этим (это работает!), Но у меня есть несколько вопросов

struct Inner<'a, 'b>{ 
    foo: &'a str, 
    bar: &'b str 
} 

trait Worker<'data, 'a, 'b> { 
    fn new (inner: &'data Inner<'a, 'b>) -> Self; 
    fn work_with_inner() { println!("works on inner");} 
} 

struct SomeWorker<'inner, 'a:'inner, 'b:'inner> { 
    inner: &'inner Inner<'a, 'b> 
} 

impl<'data, 'a, 'b> Worker<'data, 'a, 'b> for SomeWorker<'data, 'a, 'b> { 
    fn new (inner: &'data Inner<'a, 'b>) -> Self { 
     SomeWorker { 
      inner: inner 
     } 
    } 
} 

fn main() { 
} 

манежике: http://is.gd/A3ol4w

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

  2. Если нет возможности пропустить время жизни в этом признаке, это означает, что лучше всего указать все возможные сроки жизни на черту, чтобы иметь максимальную гибкость для исполнителя? Я имею в виду, что если структура SomeWorker не захочет хранить ссылку на Inner, все это, включая черту, может быть намного проще.

Увидеть, нет жизни вообще.

struct Inner<'a, 'b>{ 
    foo: &'a str, 
    bar: &'b str 
} 

trait Worker { 
    fn new (inner: &Inner) -> Self; 
    fn work_with_inner() { println!("works on inner");} 
} 

struct SomeWorker; 

impl Worker for SomeWorker { 
    fn new (inner: &Inner) -> Self { 
     SomeWorker 
    } 
} 

fn main() { 
} 

Playpen: http://is.gd/NzigjX

Вот почему я спрашиваю себя, если в качестве признака автора следует считать, что все методы, которые принимают ссылки могут в конечном итоге хранится на поле с помощью признака реализатора и, следовательно, Мне нужно указать все жизненные моменты на этом признаке, чтобы сделать это возможным для разработчиков.

ответ

5

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

Если вы хотите сопоставить значения времени жизни с параметрами жизненного цикла структуры, то вы должны поместить время жизни в этот признак. Это будет , как правило,, потому что ваш признак имеет несколько методов, которые, как ожидается, будут работать с одним и тем же значением со временем жизни. Это может быть похоже на пару геттер/сеттер. В некотором коде, который я написал, я передаю ссылки &str, на которые я держусь некоторое время, прежде чем «дорабатывать» их. Если вам нужно сохранить ссылку по какой-либо причине, тогда вам понадобится время жизни на этом значении.

В вашем случае у вас есть метод конструктора, который должен знать о времени жизни, если это делает структура. Вы можете отделить эту функцию от остальной части признака, если она действительно отличается. В вашем примере метод work_with_inner не принимает аргумент self, так что будет очень. Если вы использовали self но не должны взаимодействовать с временем жизни от Inner, он все еще может помочь:

trait WorkerBuilder<'a, 'b> { 
    fn new(inner: Inner<'a, 'b>) -> Self; 
} 

trait Worker { 
    fn do_work(&self); 
} 

#[derive(Debug)] 
struct Inner<'a, 'b>{ 
    foo: &'a str, 
    bar: &'b str, 
} 

// This does track `Inner` 
#[derive(Debug)] 
struct SomeWorker<'a, 'b>(Inner<'a, 'b>); 

impl<'a, 'b> WorkerBuilder<'a, 'b> for SomeWorker<'a, 'b> { 
    fn new(inner: Inner<'a, 'b>) -> SomeWorker<'a, 'b> { 
     SomeWorker(inner) 
    } 
} 

impl<'a, 'b> Worker for SomeWorker<'a, 'b> { 
    fn do_work(&self) { println!("Doing work, {:?}", self.0) } 
} 

// This doesn't track `Inner` 
#[derive(Debug)] 
struct DumbWorker; 

impl<'a, 'b> WorkerBuilder<'a, 'b> for DumbWorker { 
    fn new(inner: Inner<'a, 'b>) -> DumbWorker { 
     DumbWorker 
    } 
} 

fn main() {} 

Глядишь Я также применил одну вещь, которую вы можете сделать, чтобы уменьшить количество жизней ,Если у вас есть структура, которая является просто ссылкой (или ссылками и другими малыми типами Copy), нет необходимости передавать ссылку на , что struct. Ссылки являются скопируемыми, а отслеживание продолжительности жизни содержащей структуры нецелесообразно.


Редакция - Я не чувствую, что методы «конструктора» обычно полезны в признаке. Вы часто хотите предоставить другой набор или параметры, поэтому у вас есть разные типы. Возможно, ваш реальный код использует хотя бы что-то, кроме конструктора.

+0

Отличный ответ, как обычно! Отсутствующий '& self' был неаккуратным мной с примером. Это как-то привело меня к другому вопросу haha ​​http://stackoverflow.com/questions/34374149/what-type-annotations-does-rust-want-for-this-ufcs-call – Christoph

Смежные вопросы