Признак или метод, не зависящий от универсального типа

У меня есть общая структура в ржавчине, которая имеет одно общее поле, в данном случае вал и поле для конкретного типа:

struct A<T> {
    val: i32,
    t: T
}

Что я пытаюсь сделать, так это иметь метод, связанный со структурой, независимо от типа Т. Что-то, что я могу назвать так:

A::my_method()

Вместо:

A::<T>::my_method()

Я попытался реализовать трейт Получить на А<Т> и назвать его следующим образом:

struct A<T> {
    val: i32,
    t: T
}

trait Get {
    type ValType;
    fn get_val() -> Self::ValType;
}

impl<T> Get for A<T> {
    type ValType = i32;
    
    fn get_val() -> Self::ValType {
        2
    }
}

fn main() {
    let a = A {
        val: 2,
        t: 3.0
    };
    
    // This is the call I want, if possible
    println!("{:?}", A::get_val());
}

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

impl<T> Get for A<any T> {
    type ValType = i32;
    
    fn get_val() -> Self::ValType {
        2
    }
}

В некоторых сообщениях я обнаружил, что обходной путь состоит в том, чтобы иметь параметр фиктивного типа и вызывать мою функцию следующим образом:

struct DummyType;

fn main() {
    let a = A {
        val: 2,
        t: 3.0
    };
    
    // This is the call I want, if possible
    println!("{:?}", A::<DummyType>::get_val());
}

Это кажется странной проблемой. Действительно ли цель состоит в том, чтобы ускользнуть от турбофиша, или есть что-то более глубокое?

BallpointBen 22.03.2022 14:41

То, что вы реализовали, является связанной функцией, а не методом. Если вашей целью является метод, см. ответ Якуба ниже.

sudo 22.03.2022 14:50

Я ищу связанную функцию, как упомянуто @BallpointBen, чтобы эллидировать турбофиша. В текущей настройке мне может потребоваться создать один или несколько фиктивных типов, чтобы делать то, что я хочу, что я не нахожу особенно чистым.

Alexandru Placinta 22.03.2022 15:08
Как создавать пользовательские общие типы в Python (50/100 дней Python)
Как создавать пользовательские общие типы в Python (50/100 дней Python)
Помимо встроенных типов, модуль типизации в Python предоставляет возможность определения общих типов, что позволяет вам определять типы, которые могут...
0
3
56
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Чего вам, вероятно, не хватает, так это приемника метода.


pub struct A<T> {
    pub field: usize,
    pub something: T,
}

pub trait Getter {
    type Output;
    fn get(&self) -> Self::Output;
}

impl<T> Getter for A<T> {
    type Output = usize;
    fn get(&self) -> Self::Output {
        self.field
    }
}

fn main() {
    let a = A { field: 10, something: 3.0 };
    assert_eq!(a.get(), 10);
}

Тут можно вернуть состояние A и не просто константу.

Я пробовал с приемником, прежде чем публиковать вопрос, и это действительно работает (извините, что не упомянул об этом). Моя цель состоит в том, чтобы он вызывался без приемника, другими словами, чтобы обойти оператора турбофиша.

Alexandru Placinta 22.03.2022 15:07
Ответ принят как подходящий

Во-первых, ваш дизайн выглядит неправильно. Если тип является универсальным, что означает наличие неуниверсального метода?

В любом случае, вы можете использовать тип сторожевого (и вам не нужен трейт для этого, я действительно не понимаю, почему вы поставили его на первое место):

impl A<()> {
    fn get_val() -> i32 {
        2
    }
}

Компилятор автоматически определяет T как (), когда вы вызываете A::get_val().

Детская площадка.

Хорошо, я попробовал это, и с ржавчиной, похоже, все в порядке:

pub trait Get {
    type Output;
    fn get() -> Self::Output;
}

pub struct A<T>(T);

impl Get for A<()> {
    type Output = usize;
    fn get() -> Self::Output {
        2
    }
}

fn main() {
    println!("{}", A::get());
}

() — лучший выбор, так как вы хотите показать, что параметр здесь не важен для нас, но также не объявлять тип только для этого.

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