Why does the error "is not constrained by the impl trait" occur when only changing the definition of the offending type parameter?

huangapple go评论82阅读模式
英文:

Why does the error "is not constrained by the impl trait" occur when only changing the definition of the offending type parameter?

问题

这个问题是基于之前的问题构建的,可能对理解上下文有所帮助。

以下是问题中的原始特质以及最简单的实现(即对于 T: Fn() -> TR):

pub trait Ext<T> {
    type Output;
    fn call_with_tuple(self, x: T) -&gt; Self::Output;
    fn to_tuple_fn(self) -&gt; Box<dyn Fn(T) -&gt; Self::Output>;
}

impl<T: 'static, TR> Ext<()> for T
where
    T: Fn() -&gt; TR,
{
    type Output = TR;
    fn call_with_tuple(self, _: ()) -&gt; Self::Output {
        self()
    }
    fn to_tuple_fn(self) -&gt; Box<dyn Fn(()) -&gt; Self::Output> {
        Box::new(move |_| self())
    }
}

为了解决从泛型函数返回值后丢失了一些类型信息的问题(特别是 to_tuple_fn 不会保留原始值的任何特质,比如 Clone),我们可以尝试将 T: Fn() -&gt; TR 更改为 T: CloneableFn<(), TR>。这会导致错误

error[E0207]: the type parameter `TR` is not constrained by the impl trait, self type, or predicates
  --&gt; src/main.rs:52:18
   |
52 | impl<T: 'static, TR> Ext<()> for T
   |                  ^^ unconstrained type parameter

但我不明白为什么会出现这种情况,因为只有 TR 的定义发生了变化,而在特质实现的其余部分中它并未改变。

这里是演示此问题的示例链接

英文:

This question builds on a previous question, which may be useful to see for context.

Here is the original trait in question, along with the simplest implementation (i.e. for T: Fn() -&gt; TR):

pub trait Ext&lt;T&gt; {
    type Output;
    fn call_with_tuple(self, x: T) -&gt; Self::Output;
    fn to_tuple_fn(self) -&gt; Box&lt;dyn Fn(T) -&gt; Self::Output&gt;;
}

impl&lt;T: &#39;static, TR&gt; Ext&lt;()&gt; for T
where
    T: Fn() -&gt; TR,
{
    type Output = TR;
    fn call_with_tuple(self, _: ()) -&gt; Self::Output {
        self()
    }
    fn to_tuple_fn(self) -&gt; Box&lt;dyn Fn(()) -&gt; Self::Output&gt; {
        Box::new(move |_| self())
    }
}

To get around the issue where some type information is lost after a value is returned from a generic function (in particular to_tuple_fn will not preserve any traits of the original value, such as Clone), we can try to change T: Fn() -&gt; TR to be T: CloneableFn&lt;(), TR&gt;. This results in the error:

error[E0207]: the type parameter `TR` is not constrained by the impl trait, self type, or predicates
  --&gt; src/main.rs:52:18
   |
52 | impl&lt;T: &#39;static, TR&gt; Ext&lt;()&gt; for T
   |                  ^^ unconstrained type parameter

But I don't see why this is the case, as only the definition of TR change, not how it appears in the rest of the trait impl.

Here's a playground link demonstrating the issue.

答案1

得分: 1

"Fn() -> TR" 这个语法被展开成了 trait 约束 "Fn<(), Output = TR>"。"Output" 是一个关联类型。关联类型用于约束泛型参数,因此这是正确的。

但是在你的 trait 中,这不再是一个关联类型,而是一个类型参数。它们不会约束泛型参数,所以这会导致失败。

将其改为关联类型,就可以正常工作。

英文:

The syntax Fn() -&gt; TR is desugared into the trait bound Fn&lt;(), Output = TR&gt;. Output is an associated type. Associated types constrain generic parameters, so this is fine.

But with your trait, this is not an associated type anymore but a type parameter. They don't constrain generic parameters, so this fails.

Change it to be an associated type and it will work.

huangapple
  • 本文由 发表于 2023年7月27日 20:42:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76779849.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定