Rust expected dyn ToString, found f64 - rust

I am struggling with code to write containers to file. I have specified a trait bound of std::fmt::Display because any type implementing this has to_string(). f64 implements this trait, so I don't understand how this error could happen. I checked the rust issues on github and nothing appears to be there but I wanted to check my understanding before raising an issue.
type mismatch resolving `<Vec<f64> as IntoIterator>::Item == (dyn std::fmt::Display + 'static)`
expected trait object `(dyn std::fmt::Display + 'static)`
found type `f64` rustc (E0271)
Edit:
The ToString trait is what I actually tried first, and it gives the same error
type mismatch resolving `<Vec<f64> as IntoIterator>::Item == (dyn ToString + 'static)`
expected trait object `(dyn ToString + 'static)`
found type `f64` rustc (E0271)
Edit:
Added relevant code. I also have an error where the compiler complains about x not being a reference, which I haven't figured out and is why I didn't initially have the code in this question.
use std::error::Error;
// Write to a file
pub fn write_to_file<T>(data_line: T) -> Result<(), Box<dyn Error>>
where
T: IntoIterator<Item = dyn ToString> + len_trait::Len,
{
let file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.append(true)
.open("test_data/data.tsv")
.unwrap();
let mut wtr = csv::WriterBuilder::new()
.delimiter(b'\t')
.quote_style(csv::QuoteStyle::NonNumeric)
.from_writer(file);
let mut data_line_str: Vec<String> = Vec::with_capacity(data_line.len());
// into_iter() is used instead of iter() because iter() doesn't have a trait
// and into_iter() consumes the reference, not the original object
data_line
.into_iter()
.for_each(|x| data_line_str.push(x.to_string()));
wtr.write_record(&data_line_str)?;
wtr.flush()?;
Ok(())
}
// Use assertions to check for problems
#[test]
fn test_write() -> Result<(), Box<dyn Error>>
{
let test: Vec<f64> = vec![1.423, 0.61324, 123.865];
write_to_file(test)?;
// Could use assert_eq! and open file and check matching
let _remove_success = std::fs::remove_file("test_data/data.tsv");
Ok(())
}
Edit:
I've tried changing the function definition, haven't changed to use collect yet because I'm trying to pick apart how this works, and I get this error... I thought I understood but now I'm confused again.
error[E0599]: no method named `len` found for type parameter `T` in the current scope
--> src/io.rs:22:71
|
4 | pub fn write_to_file<T, I>(data_line: T) -> Result<(), Box<dyn Error>>
| - method `len` not found for this type parameter
...
22 | let mut data_line_str: Vec<String> = Vec::with_capacity(data_line.len());
| ^^^ method not found in `T`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `len`, perhaps you need to restrict type parameter `T` with one of them:
|
6 | T: IntoIterator<IntoIter = I> + ExactSizeIterator,
| +++++++++++++++++++
6 | T: IntoIterator<IntoIter = I> + FixedInitializer,
| ++++++++++++++++++
For more information about this error, try `rustc --explain E0599`.
Final edit:
I believe that I understand the issue. When I bound IntoIterator::IntoIter to ExactSizeIterator, that is specifying what the object that can be turned into an iterator (that is, implements IntoIterator) is turned into an ExactSizeIterator which at that point has a len(). So data_line may not have a len() method, but data_line.into_iter() would when I do as PitaJ suggests and use a type signature like
pub fn write_to_file<T, I>(data_line: T) -> Result<(), Box<dyn Error>>
where
T: IntoIterator<IntoIter = I>,
I: ExactSizeIterator,
<I as Iterator>::Item: ToString,

T: IntoIterator<Item = dyn ToString> + len_trait::Len,
What this says is "I expect T to be able to be converted into an iterator containing some unknown type of trait objects for ToString. That's actually a pretty complicated iterator type, and since dyn ToString is unsized, I'm not entirely confident you can ever have any valid instance of this type.
In most reasonable use cases for this function, we know the type of the iterator at compile time, so you're looking for generics, not trait objects. Consider
pub fn write_to_file<T, I>(data_line: T) -> Result<(), Box<dyn Error>>
where
T: IntoIterator<Item = I> + len_trait::Len,
I: ToString

Related

The trait bound `String: From<&T>` is not satisfied when my T is bound with Into<String>

I have the following code,
impl<T: Debug + Into<String> + Clone> TryFrom<Vec<T>> for Positionals {
type Error = &'static str;
fn try_from(mut vec: Vec<T>) -> Result<Self, Self::Error> {
let mystr: String = vec.get(0).unwrap().into();
And that code is producing this error,
error[E0277]: the trait bound `String: From<&T>` is not satisfied
--> bin/seq.rs:21:43
|
21 | let mystr: String = vec.get(0).unwrap().into();
| ^^^^ the trait `From<&T>` is not implemented for `String`
|
= note: required because of the requirements on the impl of `Into<String>` for `&T`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
I'm confused as to why this is generating an error because I have a trait bound on Vec<T> such that T must implement Into<String>, what else is required? I don't understand why this is, I remove the into(), I get
let mystr: String = vec.get(0).unwrap();
------ ^^^^^^^^^^^^^^^^^^^ expected struct `String`, found `&T`
How can I get my T in Vec<T> to String? The reason why I'm doing Vec<T> and not Vec<String> is because I want to support Vec<&str> too.
The problem with your code is that your vector gives you references, i.e. &String. While Into<String> is trivially implemented for String, it is not implemented for &String, which would require cloning. You could implement the compiler's suggestion and add a where T: From<&String>, but it'd require additional fiddling with lifetimes and would again not support &str.
To support both &str and String, you can use AsRef<str>:
impl<T: Debug + Clone + AsRef<str>> TryFrom<Vec<T>> for Positionals {
type Error = &'static str;
fn try_from(mut vec: Vec<T>) -> Result<Self, Self::Error> {
let mystr: String = vec[0].as_ref().into();
todo!()
}
}
With that both of the following compile:
Positionals::try_from(vec!["foo",]);
Positionals::try_from(vec!["foo".to_owned(),]);
Playground
Side note: you can use vec[0] instead of vec.get(0).unwrap(). (To prevent an unwanted move out of the vector, just add a borrow, i.e. &vec[0].)

Rust Error conversion for generic FromStr, unwrap errors out with unsatisfied trait bounds

I am using the thiserror crate to create a custom error type
use thiserror::Error;
/// ParseTreeError enumerates all possible errors returned by this library.
#[derive(Error, Debug)]
pub enum ParseTreeError {
/// Represents an empty source. For example, an empty text file being given
/// as input to `count_words()`.
#[error("Source contains no data")]
EmptySource,
/// Represents a failure to read from input.
#[error("Read error")]
ReadError,
}
pub struct Parser <'a, T>
where
T: FromStr + PartialEq
{
token_stream: &'a str,
marker: (usize, usize),
}
impl<'a, T> Parser<'a, T>
where
T: FromStr + PartialEq
{
fn test_parse() -> Result<(), ParseTreeError> {
let mut val = T::from_str("5").unwrap();
Ok(())
}
}
This throws the following error:
error[E0599]: the method `unwrap` exists for enum `std::result::Result<T, <T as FromStr>::Err>`, but its trait bounds were not satisfied
--> src/tree/parser.rs:65:40
|
65 | let mut val = T::from_str("5").unwrap();
| ^^^^^^ method cannot be called on `std::result::Result<T, <T as FromStr>::Err>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`<T as FromStr>::Err: Debug`
If I map the error like this
let mut val2 = T::from_str("5").map_err(|_| ParseTreeError::ReadError).unwrap();
Then no error is thrown.
If i try to use the ? operator i get the error
error[E0277]: `?` couldn't convert the error to `ParseTreeError`
--> src/tree/parser.rs:65:40
|
65 | let mut val1 = T::from_str("5")?;
| ^ the trait `From<<T as FromStr>::Err>` is not implemented for `ParseTreeError`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `from`
What do I need to do so that the ? operator can automatically convert the error to the correct error type without having to use map_err ?
Your issue is completely unrelated to thiserror, but can be reproduced via
use std::str::FromStr;
fn test_parse<T>() -> Result<(), ()>
where
T: FromStr,
{
let mut val = T::from_str("5").unwrap();
Ok(())
}
So, what's the issue? The issue is hidden away in Result's unwrap. unwrap is only available if we can somehow show the E in Result<T, E>:
// vvvvvvvvvvvvv
impl<T, E: fmt::Debug> Result<T, E> {
// ...
fn unwrap(self) -> T {
...
}
}
Where does E come from? Well, every FromStr implementation has to define the associated error type, Err. However, there are no constrains on Err. It might implement Debug, but it also might not. Since our trait bounds on test_parse say that we're fine to run over all Ts that implement just FromStr, we're too generic. We need to say that test_parse will only work for Ts that are FromStr and whose associated Err type can be shown via Debug:
use std::fmt;
use std::str::FromStr;
fn test_parse<T>() -> Result<(), ()>
where
T: FromStr,
<T as FromStr>::Err: fmt::Debug, // <<<<
{
let mut val = T::from_str("5").unwrap();
Ok(())
}
Now test_parse cannot be used with all possible FromStr implementations anymore, but only those which also implement Debug on their associated Err type, which is exactly what we needed.
For the ? operator, we need to implement From<<T as FromStr>::Err> for ParseTreeError, however, that's blocked by E0207.

The trait Extend is not implemented for Vec when partitioning an iterator

I am running into the error when calling .partition() on a vector iterator:
error[E0277]: the trait bound `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>: std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not satisfied
--> src/main.rs:9:24
|
9 | results.iter().partition(|r| r.is_ok());
| ^^^^^^^^^ the trait `std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not implemented for `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>`
|
= help: the following implementations were found:
<std::vec::Vec<T> as std::iter::Extend<&'a T>>
<std::vec::Vec<T> as std::iter::Extend<T>>
When running the following code:
use std::collections::HashSet;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn main() {
let mut results: Vec<Result<HashSet<String>>> = Default::default();
let (okays, errors): (Vec<Result<HashSet<&String>>>, Vec<_>) =
results.iter().partition(|r| r.is_ok());
}
See playground for example.
As the error message states (with namespacing removed):
the trait Extend<&Result<HashSet<String>, Box<dyn Error>>> is not implemented for Vec<Result<HashSet<&String>, Box<dyn Error>>>
You can't extend a Vec<T> with elements of type &T because they aren't the same type.
Instead, you can do one of these:
Change the type of the destination collection to Vec<&Result<HashSet<String>>> (or just Vec<_>, like your second destination type, to allow the compiler to infer the inner type).
Convert the reference to an owned value, perhaps via clone or to_owned.
Don't iterate over references to start with, using into_iter or drain instead.
However, your current type will be very hard or expensive to achieve, as you state that you want an owned Result with an owned HashMap but a reference the String.
I think the best thing is to use Itertools::partition_map and into_iter:
use itertools::Itertools; // 0.9.0
use std::collections::HashSet;
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
fn main() {
let mut results: Vec<Result<HashSet<String>>> = Default::default();
let (errors, okays): (Vec<_>, Vec<_>) = results.into_iter().partition_map(Into::into);
// let (errors, okays): (Vec<Error>, Vec<HashSet<String>>)
}
See also:
What is the difference between iter and into_iter?

The trait `rayon::iter::ParallelExtend<impl std::future::Future>` is not implemented for `std::vec::Vec [duplicate]

I am running into the error when calling .partition() on a vector iterator:
error[E0277]: the trait bound `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>: std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not satisfied
--> src/main.rs:9:24
|
9 | results.iter().partition(|r| r.is_ok());
| ^^^^^^^^^ the trait `std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not implemented for `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>`
|
= help: the following implementations were found:
<std::vec::Vec<T> as std::iter::Extend<&'a T>>
<std::vec::Vec<T> as std::iter::Extend<T>>
When running the following code:
use std::collections::HashSet;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn main() {
let mut results: Vec<Result<HashSet<String>>> = Default::default();
let (okays, errors): (Vec<Result<HashSet<&String>>>, Vec<_>) =
results.iter().partition(|r| r.is_ok());
}
See playground for example.
As the error message states (with namespacing removed):
the trait Extend<&Result<HashSet<String>, Box<dyn Error>>> is not implemented for Vec<Result<HashSet<&String>, Box<dyn Error>>>
You can't extend a Vec<T> with elements of type &T because they aren't the same type.
Instead, you can do one of these:
Change the type of the destination collection to Vec<&Result<HashSet<String>>> (or just Vec<_>, like your second destination type, to allow the compiler to infer the inner type).
Convert the reference to an owned value, perhaps via clone or to_owned.
Don't iterate over references to start with, using into_iter or drain instead.
However, your current type will be very hard or expensive to achieve, as you state that you want an owned Result with an owned HashMap but a reference the String.
I think the best thing is to use Itertools::partition_map and into_iter:
use itertools::Itertools; // 0.9.0
use std::collections::HashSet;
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
fn main() {
let mut results: Vec<Result<HashSet<String>>> = Default::default();
let (errors, okays): (Vec<_>, Vec<_>) = results.into_iter().partition_map(Into::into);
// let (errors, okays): (Vec<Error>, Vec<HashSet<String>>)
}
See also:
What is the difference between iter and into_iter?

Confused about forwarding a reference through multiple functions

I'm having trouble understanding how references get forwarded through functions. The following scenario seems to compile as expected:
trait Trait {}
struct ImplementsTrait {}
impl Trait for ImplementsTrait {}
fn foo(t: &mut Trait) {
// ... use the mutable reference
}
fn forward(t: &mut Trait) {
foo(t); // forward the type '&mut Trait' to foo
}
fn main() {
let mut t = ImplementsTrait{};
forward(&mut t); // need to pass as reference because Trait has no static size
}
However, in using the API for the capnp crate, I get unexpected behavior:
fn parse_capnp(read: &mut BufRead) {
let reader = serialize_packed::read_message(read, message::ReaderOptions::new());
Ok(())
}
fn main() {
// ... ///
let mut br = BufReader::new(f);
parse_capnp(&mut br);
Ok(())
}
error[E0277]: the trait bound `std::io::BufRead: std::marker::Sized` is not satisfied
--> src/main.rs:18:16
|
18 | let reader = serialize_packed::read_message(read, message::ReaderOptions::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::io::BufRead` does not have a constant size known at compile-time
The signature of read_message is:
pub fn read_message<R>(
read: &mut R,
options: ReaderOptions
) -> Result<Reader<OwnedSegments>>
where
R: BufRead,
It appears that read is getting passed by value when it is a &mut BufRead and read_message is expecting a &mut BufRead. The only way to get this snippet to compile for me is changing this to:
fn parse_capnp(mut read: &mut BufRead) {
let reader = serialize_packed::read_message(&mut read, message::ReaderOptions::new());
Ok(())
}
I believe I am missing something simple about the types here. To me, this appears to pass a &mut &mut BufRead, which is not the expected type, but compiles.
Could someone add clarity to the types of read and t for the two examples?
I've looked at the following threads:
Use of mut in function signature
What are Rust's exact auto-dereferencing rules?
For the first thread, I'd say the comparison to C-style pointers is faulty due to the dereferencing rules that Rust applies.
Creating a Minimal, Complete, and Verifiable example that reproduces the problem is a useful step:
use std::io::BufRead;
pub fn read_message<R>(read: &mut R)
where
R: BufRead,
{}
fn parse_capnp(read: &mut BufRead) {
read_message(read);
}
fn main() {}
error[E0277]: the trait bound `std::io::BufRead: std::marker::Sized` is not satisfied
--> src/main.rs:9:5
|
9 | read_message(read);
| ^^^^^^^^^^^^ `std::io::BufRead` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `std::io::BufRead`
note: required by `read_message`
--> src/main.rs:3:1
|
3 | / pub fn read_message<R>(read: &mut R)
4 | | where
5 | | R: BufRead,
6 | | {}
| |__^
The error message is well covered in existing questions:
Why does a generic method inside a trait require trait object to be sized?
What does "Sized is not implemented" mean?
Working with trait objects requiring sized
Why is the `Sized` bound necessary in this trait?
TL;DR: trait objects aren't guaranteed to have a size, but generics have a Sized trait bound by default.
read is getting passed by value
Yes, everything in Rust is always passed by value. Sometimes that value happens to be a reference though.
read_message is expecting a &mut BufRead
It is not. It is expecting a generic type that implements the trait BufRead. These two signatures are different:
// Reference to a concrete type
pub fn read_message<R>(read: &mut R)
where
R: BufRead,
// Trait object
pub fn read_message<R>(read: &mut BufRead)
See also:
What is the difference between <T: Trait> Box<T> and &Trait / Box<Trait>?
What makes something a "trait object"?
a &mut &mut BufRead, which is not the expected type
It's a perfectly cromulent type. BufRead is implemented for any mutable reference to any type that implements BufRead itself:
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B
Besides, in this case you don't have a &mut &mut BufRead, you have a &mut &mut R. The concrete monomorphization for the types you've shown is actually a &mut &mut Bufreader.
You can fix it by :
changing the read_message function to accept unsized types. This is fine since R is always behind a pointer:
pub fn read_message<R>(read: &mut R)
where
R: ?Sized + BufRead,
changing the parse_capnp function to take a reference to a concrete type instead of a trait object:
fn parse_capnp<R>(read: &mut R)
where
R: BufRead,
{
read_message(read);
}
changing the parse_capnp function to take a concrete type instead of a trait object. You then need to take a reference to it yourself:
fn parse_capnp<R>(mut read: R)
where
R: BufRead,
{
read_message(&mut read);
}

Resources