问题
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