嵌套特征类型、有界类型和使用 as 关键字时的冗长
Nested trait types, bounded types and verbosity in use of the as keyword
我对 as 关键字在 traits 中嵌套类型的可读性和冗长性有疑问。
我有 C++ 背景,我怀疑我的误解是由于对使用的类型系统缺乏了解 Haskell,我知道 Rust 会使用它。
在 C++ 中,模板化结构用作特征,其中类型是根据模板参数定义的。嵌套可以发生在结构等中定义其他结构类型的地方
Rust 似乎支持类似的功能。 struct MyStruct<F: Foo>
是下面较大代码片段的一部分,它根据提供的类型 F
中的类型定义成员,绑定到特征 Foo
:
struct MyStruct<F: Foo> {
// Why does this not work?
// Surely F, being constrainted to a Foo,
// has a type BAR, constrained to Bar<F>,
// has a type BAZ, constrained to Baz<F>
// data: Vec<F::BAR::BAZ>,
data: Vec< <<F as Foo>::BAR as Bar<F>>::BAZ >,
}
简而言之,当在此结构中定义成员时,似乎必须使用 <<F as Foo>::BAR as Bar<F>>::BAZ
来为编译器提供额外的类型信息。这似乎是合理的,因为编译器必须知道 F
的类型才能推断其类型。然而,在我看来,这些信息已经由这些类型的边界、结构的通用参数以及特征定义本身提供。
我确实发现 <<F as Foo>::BAR as Bar<F>>::BAZ
与 F::BAR::BAZ
相比有点难读,我想知道从代码可读性的角度来看是否有更好的处理方法?完整代码片段如下:
use std::vec::{Vec};
pub trait Foo {
type VALUE;
type BAR: Bar<Self>;
}
pub trait Bar<F: Foo> {
type BAZ: Baz<F>;
}
pub trait Baz<F: Foo> {
fn new(value: F::VALUE) -> Box<F::VALUE> {
Box::new(value)
}
}
fn main() {
struct BarImpl;
impl<F: Foo> Bar<F> for BarImpl {
type BAZ = BazImpl;
}
struct FooImpl;
impl Foo for FooImpl {
type VALUE = f64;
type BAR = BarImpl;
}
struct BazImpl { dummy: i32 };
impl<F: Foo> Baz<F> for BazImpl {};
struct MyStruct<F: Foo> {
// Why does this not work?
// Surely F, being constrainted to a Foo,
// has a type BAR, constrained to Bar<F>,
// has a type BAZ, constrained to Baz<F>
// data: Vec<F::BAR::BAZ>,
data: Vec< <<F as Foo>::BAR as Bar<F>>::BAZ >,
}
let mut s = MyStruct::<FooImpl> { data: Vec::new() };
for x in 0..5 {
let b = BazImpl{ dummy: x};
s.data.push(b);
}
println!("s.data.len() = {}", s.data.len());
}
第一关可以隐含,所以可以有Vec<<F::BAR as Bar<F>>::BAZ>
。很有可能以后规则会放宽,可以应对多层次推断合适的约束条件,但现在不是这样。
您可以创建一个type alias
type FooBarBaz<F> = <<F as Foo>::BAR as Bar<F>>::BAZ;
struct MyStruct<F: Foo> {
data: Vec< FooBarBaz<F> >,
}
我对 as 关键字在 traits 中嵌套类型的可读性和冗长性有疑问。
我有 C++ 背景,我怀疑我的误解是由于对使用的类型系统缺乏了解 Haskell,我知道 Rust 会使用它。
在 C++ 中,模板化结构用作特征,其中类型是根据模板参数定义的。嵌套可以发生在结构等中定义其他结构类型的地方
Rust 似乎支持类似的功能。 struct MyStruct<F: Foo>
是下面较大代码片段的一部分,它根据提供的类型 F
中的类型定义成员,绑定到特征 Foo
:
struct MyStruct<F: Foo> {
// Why does this not work?
// Surely F, being constrainted to a Foo,
// has a type BAR, constrained to Bar<F>,
// has a type BAZ, constrained to Baz<F>
// data: Vec<F::BAR::BAZ>,
data: Vec< <<F as Foo>::BAR as Bar<F>>::BAZ >,
}
简而言之,当在此结构中定义成员时,似乎必须使用 <<F as Foo>::BAR as Bar<F>>::BAZ
来为编译器提供额外的类型信息。这似乎是合理的,因为编译器必须知道 F
的类型才能推断其类型。然而,在我看来,这些信息已经由这些类型的边界、结构的通用参数以及特征定义本身提供。
我确实发现 <<F as Foo>::BAR as Bar<F>>::BAZ
与 F::BAR::BAZ
相比有点难读,我想知道从代码可读性的角度来看是否有更好的处理方法?完整代码片段如下:
use std::vec::{Vec};
pub trait Foo {
type VALUE;
type BAR: Bar<Self>;
}
pub trait Bar<F: Foo> {
type BAZ: Baz<F>;
}
pub trait Baz<F: Foo> {
fn new(value: F::VALUE) -> Box<F::VALUE> {
Box::new(value)
}
}
fn main() {
struct BarImpl;
impl<F: Foo> Bar<F> for BarImpl {
type BAZ = BazImpl;
}
struct FooImpl;
impl Foo for FooImpl {
type VALUE = f64;
type BAR = BarImpl;
}
struct BazImpl { dummy: i32 };
impl<F: Foo> Baz<F> for BazImpl {};
struct MyStruct<F: Foo> {
// Why does this not work?
// Surely F, being constrainted to a Foo,
// has a type BAR, constrained to Bar<F>,
// has a type BAZ, constrained to Baz<F>
// data: Vec<F::BAR::BAZ>,
data: Vec< <<F as Foo>::BAR as Bar<F>>::BAZ >,
}
let mut s = MyStruct::<FooImpl> { data: Vec::new() };
for x in 0..5 {
let b = BazImpl{ dummy: x};
s.data.push(b);
}
println!("s.data.len() = {}", s.data.len());
}
第一关可以隐含,所以可以有Vec<<F::BAR as Bar<F>>::BAZ>
。很有可能以后规则会放宽,可以应对多层次推断合适的约束条件,但现在不是这样。
您可以创建一个type alias
type FooBarBaz<F> = <<F as Foo>::BAR as Bar<F>>::BAZ;
struct MyStruct<F: Foo> {
data: Vec< FooBarBaz<F> >,
}