Why does the compiler claim that a generic doesn't implement `Display` even though it should?












10















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)
})
}
}
}
}


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).



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);
}


This code produces a compilation error:



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 key line seems to be this:



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


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.



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?










share|improve this question

























  • It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

    – Francis Gagné
    Nov 18 '18 at 20:48






  • 1





    This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

    – Sven Marnach
    Nov 18 '18 at 20:52






  • 1





    See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

    – Sven Marnach
    Nov 18 '18 at 21:19











  • You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

    – Lucretiel
    Nov 18 '18 at 22:48






  • 1





    @Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

    – Sven Marnach
    Nov 19 '18 at 7:38
















10















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)
})
}
}
}
}


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).



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);
}


This code produces a compilation error:



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 key line seems to be this:



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


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.



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?










share|improve this question

























  • It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

    – Francis Gagné
    Nov 18 '18 at 20:48






  • 1





    This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

    – Sven Marnach
    Nov 18 '18 at 20:52






  • 1





    See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

    – Sven Marnach
    Nov 18 '18 at 21:19











  • You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

    – Lucretiel
    Nov 18 '18 at 22:48






  • 1





    @Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

    – Sven Marnach
    Nov 19 '18 at 7:38














10












10








10








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)
})
}
}
}
}


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).



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);
}


This code produces a compilation error:



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 key line seems to be this:



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


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.



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?










share|improve this question
















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)
})
}
}
}
}


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).



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);
}


This code produces a compilation error:



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 key line seems to be this:



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


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.



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?







rust formatting traits






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 18 '18 at 19:54







Lucretiel

















asked Nov 18 '18 at 19:46









LucretielLucretiel

813925




813925













  • It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

    – Francis Gagné
    Nov 18 '18 at 20:48






  • 1





    This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

    – Sven Marnach
    Nov 18 '18 at 20:52






  • 1





    See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

    – Sven Marnach
    Nov 18 '18 at 21:19











  • You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

    – Lucretiel
    Nov 18 '18 at 22:48






  • 1





    @Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

    – Sven Marnach
    Nov 19 '18 at 7:38



















  • It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

    – Francis Gagné
    Nov 18 '18 at 20:48






  • 1





    This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

    – Sven Marnach
    Nov 18 '18 at 20:52






  • 1





    See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

    – Sven Marnach
    Nov 18 '18 at 21:19











  • You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

    – Lucretiel
    Nov 18 '18 at 22:48






  • 1





    @Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

    – Sven Marnach
    Nov 19 '18 at 7:38

















It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

– Francis Gagné
Nov 18 '18 at 20:48





It looks like the compiler is treating for<'a> Display as different from Display. This might be a bug in the compiler.

– Francis Gagné
Nov 18 '18 at 20:48




1




1





This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

– Sven Marnach
Nov 18 '18 at 20:52





This indeed looks like a shortcoming in the compiler to me. You are right that the item type is &&str, as you can easily verify by trying to compile let _: <&Vec<&str> as IntoIterator>::Item = ();. And &&str definitely does implement Display, as can be verified by adding <&&str as fmt::Display>::fmt(&&"hello", f)?; to the body of fmt(). So this should definitely work. My guess is that <&'a std::vec::Vec<&str> as std::iter::IntoIterator>::Item isn't correctly normalized to &'a &str for some reason.

– Sven Marnach
Nov 18 '18 at 20:52




1




1





See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

– Sven Marnach
Nov 18 '18 at 21:19





See also github.com/rust-lang/rust/issues/24159 and the issues linked there. Often this can be worked around by adding an additional type parameter for the item type, and forcing it to be the actual item type by changing the trait bound IntoIterator to IntoIterator<Item = T>, where T is the new type parameter. This doesn't work int his case, though, due to the HRTBs.

– Sven Marnach
Nov 18 '18 at 21:19













You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

– Lucretiel
Nov 18 '18 at 22:48





You actually can do that in this case; I was able to try <T: Display> ... where &'a C: IntoIterator<Item=T>. However, I got a different and somehow even less useful error message about unfulfilled lifetime bounds.

– Lucretiel
Nov 18 '18 at 22:48




1




1





@Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

– Sven Marnach
Nov 19 '18 at 7:38





@Lucretiel The reason this does not work is because of the lifetime of Item. In your example, the item type is &&str, but annoted with the lifetime of the HRTB, it would have to be &'a &str for all lifetimes 'a, which of course is impossible. That's what I meant in my previous comment.

– Sven Marnach
Nov 19 '18 at 7:38












1 Answer
1






active

oldest

votes


















8














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: ", ",
});
}





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53364798%2fwhy-does-the-compiler-claim-that-a-generic-doesnt-implement-display-even-thou%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    8














    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: ", ",
    });
    }





    share|improve this answer




























      8














      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: ", ",
      });
      }





      share|improve this answer


























        8












        8








        8







        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: ", ",
        });
        }





        share|improve this answer













        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: ", ",
        });
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 18 '18 at 21:16









        dtolnaydtolnay

        3,50711633




        3,50711633
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53364798%2fwhy-does-the-compiler-claim-that-a-generic-doesnt-implement-display-even-thou%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini