为什么编译器声称来自更高等级特征绑定的关联类型没有实现 `Display`,即使它应该实现? [英] Why does the compiler claim that an associated type from a higher-ranked trait bound doesn't implement `Display` even though it should?

查看:31
本文介绍了为什么编译器声称来自更高等级特征绑定的关联类型没有实现 `Display`,即使它应该实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个实现字符串连接的库;也就是说,打印由分隔符分隔的容器的所有元素.我的基本设计如下:

I'm building a library that implements string joins; that is, printing all the elements of a container separated by a separator. My basic design looks like this:

use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Join<Container, Sep> {
    container: Container,
    sep: Sep,
}

impl<Container, Sep> fmt::Display for Join<Container, Sep>
where
    for<'a> &'a Container: IntoIterator,
    for<'a> <&'a Container as IntoIterator>::Item: fmt::Display,
    Sep: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut iter = self.container.into_iter();

        match iter.next() {
            None => Ok(()),
            Some(first) => {
                first.fmt(f)?;

                iter.try_for_each(move |element| {
                    self.sep.fmt(f)?;
                    element.fmt(f)
                })
            }
        }
    }
}

这个 trait 实现编译时没有抱怨.注意 &'a C: IntoIterator 上的界限.许多容器实现了 IntoIterator 以作为对自身的引用,以允许迭代对包含项的引用(例如,Vec 实现了它这里).

This trait implementation compiles without complaint. Notice the bound on &'a C: IntoIterator. Many containers implement IntoIterator for a reference to themselves, to allow for iterating over references to the contained items (for instance, Vec implements it here).

然而,当我真正尝试使用我的 Join 结构时,我得到了一个不满意的 trait bound:

However, when I actually try to use my Join struct, I get an unsatisfied trait bound:

fn main() {
    let data = vec!["Hello", "World"];
    let join = Join {
        container: data,
        sep: ", ",
    };
    println!("{}", join);
}

此代码产生编译错误:

error[E0277]: `<&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item` doesn't implement `std::fmt::Display`
  --> src/main.rs:38:20
   |
38 |     println!("{}", join);
   |                    ^^^^ `<&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item` cannot be formatted with the default formatter
   |
   = help: the trait `for<'a> std::fmt::Display` is not implemented for `<&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: required because of the requirements on the impl of `std::fmt::Display` for `Join<std::vec::Vec<&str>, &str>`
   = note: required by `std::fmt::Display::fmt`

关键线似乎是这样的:

the trait `for<'a> std::fmt::Display` is not implemented for `<&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item`

不幸的是,编译器实际上并没有告诉我 Item 类型是什么,而是基于我对 the docs,它似乎是 &T,在这种情况下意味着 &&str.

Unfortunately, the compiler doesn't actually tell me what the Item type is, but based on my reading of the docs, it appears to be &T, which in this case means &&str.

为什么编译器不认为 &&str 实现了 Display?我已经用许多其他类型尝试过这个,比如 usizeString,但它们都不起作用;它们都因相同的错误而失败.我知道这些引用类型不直接实现Display,但是实现应该通过deref强制自动获取,对吗?

Why doesn't the compiler think that &&str implements Display? I've tried this with many other types, like usize and String, and none of them work; they all fail with the same error. I know that these reference type don't directly implement Display, but the implementation should be picked up automatically through deref coercion, right?

推荐答案

看起来像 a编译器限制.您现在可以通过根据表示显示与生命周期"的私有帮助程序特征编写 impl 边界来解决它.这使编译器能够看到 for<'a>private::Display<'a> 暗示 fmt::Display.

Seems like a compiler limitation. You can work around it for now by writing the impl bound in terms of a private helper trait that represents "display with lifetime". This enables the compiler to see that for<'a> private::Display<'a> implies fmt::Display.

use std::fmt;

pub struct Join<Container, Sep> {
    container: Container,
    sep: Sep,
}

mod private {
    use std::fmt;
    pub trait Display<'a>: fmt::Display {}
    impl<'a, T> Display<'a> for T where T: fmt::Display {}
}

impl<Container, Sep> fmt::Display for Join<Container, Sep>
where
    for<'a> &'a Container: IntoIterator,
    for<'a> <&'a Container as IntoIterator>::Item: private::Display<'a>,
    Sep: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut iter = self.container.into_iter();

        match iter.next() {
            None => Ok(()),
            Some(first) => {
                first.fmt(f)?;

                iter.try_for_each(move |element| {
                    self.sep.fmt(f)?;
                    element.fmt(f)
                })
            }
        }
    }
}

fn main() {
    println!(
        "{}",
        Join {
            container: vec!["Hello", "World"],
            sep: ", ",
        }
    );
}

这篇关于为什么编译器声称来自更高等级特征绑定的关联类型没有实现 `Display`,即使它应该实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆