Как я могу использовать супертрат BorrowMut для доступа к полям структуры в методе по умолчанию? - PullRequest
0 голосов
/ 26 ноября 2018

Рассмотрим следующий код Rust

trait Trait {
    fn show_name(&self) {}
}

struct Foo {
    name: String,
    things_and_stuff: usize,
}

impl Trait for Foo {
    fn show_name(&self) {
        println!("{}", self.name);
    }
}

struct Bar {
    name: String,
    other_field: i32,
}

impl Trait for Bar {
    fn show_name(&self) {
        println!("{}", self.name);
    }
}

Две функции show_name имеют одинаковый код.Было бы удобно, если бы я мог поместить этот метод в качестве метода по умолчанию в Trait, но это невозможно, потому что черты не могут получить доступ к полям структуры.

Мы могли бы объявить метод get_name(&self) -> &str в Trait и реализоватьэто на Foo и Bar, но это не решает проблему дублирования кода, потому что обе реализации get_name будут одинаковыми.

Было бы неплохо избежать дублирования кода. Еще один вопрос уже задавал вопрос о том, возможен ли полевой доступ по признакам, и ответ был в основном "нет".Тем не менее, я нашел комментарий на форуме ржавчины-внутренности, который предполагает, что уже возможно.Вот код:

struct Fields {
    name: String,
}

trait Trait: BorrowMut<Fields> {
    // methods go here
}

impl<T> Trait for T where T: BorrowMut<Fields> {}

Предположительно, есть способ сделать тип T be BorrowMut<Fields> и использовать его, чтобы позволить Trait получить доступ к полям Fields, но пока яЯ не уверен, как это будет работать.

Каким образом приведенный выше фрагмент кода должен решить проблему получения доступа к полю в чертах?


Я знаю, что обсуждаются вопросы добавления поля.доступ к чертам языка ( rust-internals , RFC , еще один RFC ), но я хотел бы знать, что возможно сейчас.

1 Ответ

0 голосов
/ 26 ноября 2018

ответ был в основном "нет"

Ответ фактически говорит (выделение мое):

Реализация по умолчанию может использовать только методы, которые определенына черте или в супер черте .

Вот что делает ваш фрагмент:

trait Trait: BorrowMut<Fields>

Чтобы он работал, следуйте советамиз сообщения, на которое вы ссылаетесь:

все типы, которые выбирают для реализации BorrowMut<Foo>

Таким образом, вам необходимо реализовать черту для каждого из ваших типов.Я переключился на Borrow, потому что здесь вам не нужна изменчивость:

use std::borrow::Borrow;

struct Fields {
    name: String,
}

trait Trait: Borrow<Fields> {
    fn show_name(&self) {
        let fields: &Fields = self.borrow();
        println!("{}", fields.name);
    }
}

struct Foo {
    fields: Fields,
    things_and_stuff: usize,
}

impl Borrow<Fields> for Foo {
    fn borrow(&self) -> &Fields {
        &self.fields
    }
}

struct Bar {
    fields: Fields,
    other_field: i32,
}

impl Borrow<Fields> for Bar {
    fn borrow(&self) -> &Fields {
        &self.fields
    }
}

impl<T> Trait for T where T: Borrow<Fields> {}

Я почти уверен, что вам не понравится это решение, потому что

неУстраните проблему наличия дублированного кода, поскольку обе реализации [...] будут одинаковыми

Вы можете предпочесть написать макрос, если ваша цель - уменьшить количество дублирующих символов в вашем коде.

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...