How can I have a struct which is only used for its internal constant?

安稳与你 提交于 2020-01-15 05:47:11

问题


I need to encapsulate constants in the Rust type system. Ideally, RFC2000 would be ready, but in its absence, and since I only need a restricted set of constants, I can implement something close to what I need:

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());
}

This prints out 200 as desired - that is, the constant value comes from the type that is passed in at instantiation inside main.

Now, this is a bit warty as it requires an instance of X to be created in the struct, which I call template, which is then unused so I get a compiler warning.

If one removes the template field, which is the ideal API, then the compiler complains about an unused parameter X on struct MyType < X: U32Const >. If I get rid of the X parameter on struct MyType, I then get an unexpected type argument on MyType in the the impl block.

Is there some way I can do what I'm trying to do that keeps the compiler happy? Effectively I want a struct which is only used for its internal const.


回答1:


Instead of giving a phantom variable into a struct, using associated types might do the trick,

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 (with multiple const implementations)




回答2:


You can get rid of the compiler warning by declaring template to have type 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());
}

playground

You still need to initialize it, but it doesn't use any memory and the compiler won't complain when you don't use it.



来源:https://stackoverflow.com/questions/58286148/how-can-i-have-a-struct-which-is-only-used-for-its-internal-constant

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!