Which is better between direct const value parameter or const inside trait to generic parameter?
⚓ Rust 📅 2026-02-20 👤 surdeus 👁️ 1I have two versions of the code
In the first version, I pass the numeric value directly to a const value in the struct, then use the Into trait
use std::marker::PhantomData;
trait Validator<T> {
fn validate(val: &T) -> Result<(), &'static str>;
}
struct Validated<T, V: Validator<T>>(T, PhantomData<V>);
impl<T, V: Validator<T>> Validated<T, V> {
fn new(val: T) -> Result<Self, &'static str> {
V::validate(&val)?;
Ok(Self(val, PhantomData))
}
fn get(&self) -> &T {
&self.0
}
fn take(self) -> T {
self.0
}
}
struct Min<const N: i128>;
impl<T, const N: i128> Validator<T> for Min<N>
where T: PartialOrd + Copy + Into<i128> {
fn validate(val: &T) -> Result<(), &'static str> {
if (*val).into() >= N {
return Ok(());
}
Err("Value too small")
}
}
struct Tes {
val: Validated<i32, Min<10>>
}
fn main() -> Result<(), &'static str> {
let tes = Tes {
val: Validated::new(20)?
};
println!("{}", tes.val.take());
Ok(())
}
In the second version, I define a trait containing a const variable and pass that trait into the struct's generic parameter
use std::marker::PhantomData;
trait Validator<T> {
fn validate(val: &T) -> Result<(), &'static str>;
}
struct Validated<T, V: Validator<T>>(T, PhantomData<V>);
impl<T, V: Validator<T>> Validated<T, V> {
fn new(val: T) -> Result<Self, &'static str> {
V::validate(&val)?;
Ok(Self(val, PhantomData))
}
fn get(&self) -> &T {
&self.0
}
fn take(self) -> T {
self.0
}
}
trait Num<T> {
const val: T;
}
struct Min<N>(PhantomData<N>);
impl<T, N> Validator<T> for Min<N>
where
T: PartialOrd + Copy,
N: Num<T>
{
fn validate(val: &T) -> Result<(), &'static str> {
if *val >= N::val {
return Ok(());
}
Err("Value too small")
}
}
struct Tes {
val: Validated<i32, Min<Numm>>
}
struct Numm;
impl Num<i32> for Numm {
const val: i32 = 10;
}
fn main() -> Result<(), &'static str> {
let tes = Tes {
val: Validated::new(20)?
};
println!("{}", tes.val.take());
Ok(())
}
My goal is to centralize the minimum value, so callers don't have to specify it repeatedly to reducing the risk of inconsistency. I also want the value to be protected, only overridable via ::new() to ensure that everyone creating new value uses a consistent minimum value
Which approach is better?
2 posts - 2 participants
🏷️ Rust_feed