关联类型的等式约束的替代方案
Alternative to equality constraints for associated types
我正在尝试用 Rust 编写:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1: Foo, F2: Foo> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo> Bar<F1, F2> {
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
它拒绝编译,因为 F1::T
可能与 F2::T
不同,使相等性变得毫无意义。我希望能够通过写这个来解决这个问题:
impl<F1: Foo, F2: Foo> Bar<F1, F2>
where
F1::T = F2::T
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
但这告诉我尚不支持等式约束,请参考 this issue。由于它自 2014 年底开始开放,我怀疑它不会很快推出。
我可以做到,它会编译:
struct Bar<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> {
f1: F1,
f2: F2,
}
impl<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> Bar<T, F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
但随后我向结构 Bar
添加了一个额外的通用参数。如果 Foo
有多个我想以这种方式约束的关联类型,那么它会变得有点混乱。
我的问题是:
- 这真的是我可以通过添加附加类型参数
T
使 Bar
'more generic' 强制执行此约束的唯一方法吗?
- 这是解决这个问题的最惯用的方法吗?
编辑:
我意识到我把我的例子简化了太多。
假设我实际上有一个 Bar
,它有一个关联的 Baz
,一个关联的 Foo
,一个关联的 T
。
有点啰嗦,举个例子:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1: Baz, B2: Baz> {
b1: B1,
b2: B2,
}
impl<B1: Baz, B2: Baz> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
当然它仍然无法编译,因为 get_inner_t
中的 T
可能不同。我真的很想允许两个 Baz
不同,Foo
不同,但限制它们的 T
相同。
我试图通过写作
来调整给出的答案
impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
但这给出了这个编译错误:
Compiling type_bindings v0.1.0 (/home/harry/coding/rust_sandbox/type_bindings)
error: expected one of `(`, `,`, `::`, `<`, or `>`, found `=`
--> src/main.rs:18:38
|
18 | impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
| ^ expected one of `(`, `,`, `::`, `<`, or `>`
error: aborting due to previous error
error: could not compile `type_bindings`
To learn more, run the command again with --verbose.
如果不允许关联类型的这种多级提取?
您可以“提取”关联类型:
struct Bar<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> Bar<F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
对于您的编辑,您可以使用一些类型别名来清理语法(不是必需的但更好)然后使用 impl
或向 impl 添加另一个泛型(这不会使结构更通用的,所以它不会 运行 进入相同的问题,但是它不会让你在结构上设置界限):
type GetT<T> = <T as Foo>::T;
type GetF<T> = <T as Baz>::F;
impl<B1: Baz, B2: Baz<F = impl Foo<T = GetT<GetF<B1>>>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
或
impl<T: PartialEq, B1: Baz<F = impl Foo<T = T>>, B2: Baz<F = impl Foo<T = T>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
虽然@Aplet123 指出的所有内容都是有效的,但我认为这是一种在语法上更简洁的编写方式。
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
f1: F1,
f2: F2,
}
impl<F1, F2> Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
b1: B1,
b2: B2,
}
impl<B1, B2> Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
我正在尝试用 Rust 编写:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1: Foo, F2: Foo> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo> Bar<F1, F2> {
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
它拒绝编译,因为 F1::T
可能与 F2::T
不同,使相等性变得毫无意义。我希望能够通过写这个来解决这个问题:
impl<F1: Foo, F2: Foo> Bar<F1, F2>
where
F1::T = F2::T
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
但这告诉我尚不支持等式约束,请参考 this issue。由于它自 2014 年底开始开放,我怀疑它不会很快推出。
我可以做到,它会编译:
struct Bar<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> {
f1: F1,
f2: F2,
}
impl<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> Bar<T, F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
但随后我向结构 Bar
添加了一个额外的通用参数。如果 Foo
有多个我想以这种方式约束的关联类型,那么它会变得有点混乱。
我的问题是:
- 这真的是我可以通过添加附加类型参数
T
使Bar
'more generic' 强制执行此约束的唯一方法吗? - 这是解决这个问题的最惯用的方法吗?
编辑:
我意识到我把我的例子简化了太多。
假设我实际上有一个 Bar
,它有一个关联的 Baz
,一个关联的 Foo
,一个关联的 T
。
有点啰嗦,举个例子:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1: Baz, B2: Baz> {
b1: B1,
b2: B2,
}
impl<B1: Baz, B2: Baz> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
当然它仍然无法编译,因为 get_inner_t
中的 T
可能不同。我真的很想允许两个 Baz
不同,Foo
不同,但限制它们的 T
相同。
我试图通过写作
来调整给出的答案impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
但这给出了这个编译错误:
Compiling type_bindings v0.1.0 (/home/harry/coding/rust_sandbox/type_bindings)
error: expected one of `(`, `,`, `::`, `<`, or `>`, found `=`
--> src/main.rs:18:38
|
18 | impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
| ^ expected one of `(`, `,`, `::`, `<`, or `>`
error: aborting due to previous error
error: could not compile `type_bindings`
To learn more, run the command again with --verbose.
如果不允许关联类型的这种多级提取?
您可以“提取”关联类型:
struct Bar<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> Bar<F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
对于您的编辑,您可以使用一些类型别名来清理语法(不是必需的但更好)然后使用 impl
或向 impl 添加另一个泛型(这不会使结构更通用的,所以它不会 运行 进入相同的问题,但是它不会让你在结构上设置界限):
type GetT<T> = <T as Foo>::T;
type GetF<T> = <T as Baz>::F;
impl<B1: Baz, B2: Baz<F = impl Foo<T = GetT<GetF<B1>>>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
或
impl<T: PartialEq, B1: Baz<F = impl Foo<T = T>>, B2: Baz<F = impl Foo<T = T>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
虽然@Aplet123 指出的所有内容都是有效的,但我认为这是一种在语法上更简洁的编写方式。
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
f1: F1,
f2: F2,
}
impl<F1, F2> Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
b1: B1,
b2: B2,
}
impl<B1, B2> Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}