Как я могу иметь структуру, которая используется только для его внутренней константы? - PullRequest
2 голосов
/ 08 октября 2019

Мне нужно инкапсулировать константы в системе типов Rust. В идеале RFC2000 будет готов, но при его отсутствии, и, поскольку мне нужен только ограниченный набор констант, я могу реализовать что-то близкое к тому, что мне нужно:

trait U32Const {
    const VAL: u32;
}

struct U32Const10;
impl U32Const for U32Const10 {
    const VAL: u32 = 10;
}

struct MyType<X: U32Const> {
    val: u32,
    template: X,
}

impl<X: U32Const> MyType<X> {
    fn do_something(&self) -> u32 {
        self.val * X::VAL
    }
}

fn main() {
    let a = MyType::<U32Const10> {
        val: 20,
        template: U32Const10 {},
    };
    println!("{}", a.do_something());
}

Это печатаетout 200 по желанию - то есть значение константы происходит от типа, который передается при создании экземпляра внутри main.

Теперь, это немного бородавчато, поскольку требует экземпляра Xбыть созданным в структуре, которую я называю template, которая затем не используется, поэтому я получаю предупреждение компилятора.

Если удалить поле template, которое является идеальным API, то компилятор жалуетсяо неиспользованном параметре X на struct MyType < X: U32Const >. Если я избавлюсь от параметра X на struct MyType, я получу unexpected type argument на MyType в блоке impl.

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

Ответы [ 2 ]

4 голосов
/ 08 октября 2019

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

trait U32Const {
    type U32;
    const VAL: Self::U32;
}

struct U32Const10;

impl U32Const for U32Const10 {
    type U32 = u32;
    const VAL: Self::U32 = 10;
}

struct MyType<X: U32Const> {
    val: X::U32,
}

impl<X: U32Const<U32 = u32>> MyType<X> {
    fn do_something(&self) -> X::U32 {
        self.val * X::VAL
    }
}

fn main() {
    let a = MyType::<U32Const10> { val: 20 };
    println!("{}", a.do_something());
}

Playground (с несколькими реализациями const)

1 голос
/ 08 октября 2019

Вы можете избавиться от предупреждения компилятора, объявив template типом PhantomData::<X>:

use std::marker::PhantomData;

trait U32Const {
    const VAL: u32;
}

struct U32Const10;
impl U32Const for U32Const10 {
    const VAL: u32 = 10;
}

struct MyType<X: U32Const> {
    val: u32,
    template: PhantomData::<X>,
}

impl<X: U32Const> MyType<X> {
    fn do_something(&self) -> u32 {
        self.val * X::VAL
    }
}

fn main() {
    let a = MyType::<U32Const10> {
        val: 20,
        template: PhantomData,
    };
    println!("{}", a.do_something());
}

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

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

...