特征内的常量表达式?
Const expressions inside trait?
我有这样的特质:
pub trait Buf<const N: usize> {
fn to_buf(&self) -> [u8; N];
fn from_buf(buf: [u8; N]) -> Self;
}
但是我想做这样的事情:
trait Buf {
const N: usize;
fn to_buf(&self) -> [u8; Self::N];
fn from_buf(buf: [u8; Self::N]) -> Self;
}
它给我这个错误 (playground):
|
| fn to_buf(&self) -> [u8; Self::N];
| ^^^^^^^ cannot perform const operation using `Self`
|
= note: type parameters may not be used in const expressions
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
可能吗?
您可以使用 <T: Buf<8>>
签名,例如
fn a<T: Buf<8>>(buf: T) {
println!("{:#?}", buf.to_buf());
}
或运行
#![feature(trait_alias)]
trait Buf8 = Buf<8>;
fn a<T: Buf8>(buf: T) {
println!("{:#?}", buf.to_buf());
}
在实验生锈中。
经过一些研究,我发现,在夜间,Rust 允许我们使用泛型 const 表达式,在这个 (#![feature(generic_const_exprs)]
) 特性标志下,
但是,这还远未稳定。
#![allow(warnings)]
#![feature(generic_const_exprs)]
trait Buf {
const N: usize;
fn to_buf(&self) -> [u8; Self::N];
fn from_buf(buf: [u8; Self::N]) -> Self;
}
macro_rules! impl_trait {
($name:ident for $($t:ty:$N:literal)*) => ($(
impl $name for $t {
const N: usize = $N;
fn to_buf(&self) -> [u8; $N] {
self.to_le_bytes()
}
fn from_buf(bytes: [u8; $N]) -> Self {
Self::from_le_bytes(bytes)
}
}
)*)
}
impl_trait!(Buf for u8:1 u16:2 u32:4 i8:1 i16:2 i32:4);
fn test<T: Buf>(buf: T, rhs: [u8; T::N])
where
[u8; T::N]:,
{
assert_eq!(buf.to_buf(), rhs);
}
fn main() {
test(123_u8, [123]);
test(123_u16, [123, 0]);
test(123_u32, [123, 0, 0, 0]);
test(-123i8, [133]);
test(-123i16, [133, 255]);
test(-123i32, [133, 255, 255, 255]);
}
我有这样的特质:
pub trait Buf<const N: usize> {
fn to_buf(&self) -> [u8; N];
fn from_buf(buf: [u8; N]) -> Self;
}
但是我想做这样的事情:
trait Buf {
const N: usize;
fn to_buf(&self) -> [u8; Self::N];
fn from_buf(buf: [u8; Self::N]) -> Self;
}
它给我这个错误 (playground):
|
| fn to_buf(&self) -> [u8; Self::N];
| ^^^^^^^ cannot perform const operation using `Self`
|
= note: type parameters may not be used in const expressions
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
可能吗?
您可以使用 <T: Buf<8>>
签名,例如
fn a<T: Buf<8>>(buf: T) {
println!("{:#?}", buf.to_buf());
}
或运行
#![feature(trait_alias)]
trait Buf8 = Buf<8>;
fn a<T: Buf8>(buf: T) {
println!("{:#?}", buf.to_buf());
}
在实验生锈中。
经过一些研究,我发现,在夜间,Rust 允许我们使用泛型 const 表达式,在这个 (#![feature(generic_const_exprs)]
) 特性标志下,
但是,这还远未稳定。
#![allow(warnings)]
#![feature(generic_const_exprs)]
trait Buf {
const N: usize;
fn to_buf(&self) -> [u8; Self::N];
fn from_buf(buf: [u8; Self::N]) -> Self;
}
macro_rules! impl_trait {
($name:ident for $($t:ty:$N:literal)*) => ($(
impl $name for $t {
const N: usize = $N;
fn to_buf(&self) -> [u8; $N] {
self.to_le_bytes()
}
fn from_buf(bytes: [u8; $N]) -> Self {
Self::from_le_bytes(bytes)
}
}
)*)
}
impl_trait!(Buf for u8:1 u16:2 u32:4 i8:1 i16:2 i32:4);
fn test<T: Buf>(buf: T, rhs: [u8; T::N])
where
[u8; T::N]:,
{
assert_eq!(buf.to_buf(), rhs);
}
fn main() {
test(123_u8, [123]);
test(123_u16, [123, 0]);
test(123_u32, [123, 0, 0, 0]);
test(-123i8, [133]);
test(-123i16, [133, 255]);
test(-123i32, [133, 255, 255, 255]);
}