Help understand generics with usize conversion

I'm trying to do some exercises and I got stuck in this.

I don't know how to resolve it.

I want to create a struct that can hold an array of a variety of number types.
And for the new fn I want to pass a number and the fn does the work for conversion.
Then I want to create a vec where the value is the same as the index.

right now the error that I get when instantiating the function.

let veci32: MyStruct<i32> = MyStruct::new(10);
                            ^^^^^^^^^^^^^^^^^^ the trait `From<usize>` is not implemented for `i32`
let vecu32: MyStruct<u32> = MyStruct::new(10);
                            ^^^^^^^^^^^^^^^^^^ the trait `From<usize>` is not implemented for `u32`
let veci64: MyStruct<i64> = MyStruct::new(10);
                            ^^^^^^^^^^^^^^^^^^ the trait `From<usize>` is not implemented for `i64`
#[derive(Debug)]
struct MyStruct<T>(Vec<T>);

impl<T> MyStruct<T> 
where T: From<usize>{

	fn new(size: usize) -> MyStruct<T>{
		let mut vec: Vec<T> = Vec::with_capacity(size);

		for i in 0..size {
			let value = T::try_from(i).unwrap();
			vec.push(value);
		}

		MyStruct(vec)
	}
}

fn main() {

	let veci32: MyStruct<i32> = MyStruct::new(10);
	let vecu32: MyStruct<u32> = MyStruct::new(10);
	let veci64: MyStruct<i64> = MyStruct::new(10);

	println!("{:?}", veci32);
	println!("{:?}", vecu32);
	println!("{:?}", veci64);

}

I'm not interested in just get a working version from this code, I want to understand.
Right now I don't know what to look, or what to read, I read the pages from the documentation about From/Into TryFrom/TryInto youtube videos and I still don't know how to recognize whats wrong.

What can I read/watch to get a better understanding of what's happening?

Thanks.

the compile error message literally says whats wrong:

From<usize> is not implemented for type i32 / u32 / i64

you probably want TryFrom instead of From:

 impl<T> MyStruct<T> 
-where T: From<usize>{
+where T: TryFrom<usize>{
 //...
 }
1 Like

The From trait is only used for conversions that can never fail. However, on 64-bit systems, 18446744073709551615 is a valid value for usize, but that value does not fit in i32, u32, or i64.

3 Likes

Another thing that could help is to look at the doc for i32 and see what traits are implemented for it. The Trait Implementations section has this info, but it is usually easier to scroll down in the panel on the left to see the list of implemented traits.

For i32 there are a lot of traits implemented, but if you look through it you can see that From<T> is implemented when the size of T fits in an i32, which means the value can always be converted. But there is no From<usize> because it is larger than an i32. This matches what @alice said.

If you scroll down further (much further) you can see the TryFrom<T> implementations for i32, and there is a TryFrom<usize>.

1 Like

From your code, I suppose that you understand the purpose of try_from(), to perform a conversion that might fail.

The problem with your code, then, is that the where bound demands not just that the type implements TryFrom, but that it implements From. From implies TryFrom, so your try_from() call compiles, but the calls to new don't compile because calling it requires the stricter From bound which isn't met for the particular integer types you are using.

So, if you change the bound to T: TryFrom<usize>, then new() only demands what it actually needs, and the code should compile.

2 Likes

Can't mention more than two people.

nerditation
The code with From instead of TryFrom was a copy error, I was trying things while writing the post and pasted the wrong one. But even with the TryFrom the error is similar and shows a new error.

alice that's I understand, thanks.

jumpnbrownweasel Ok, I understood that, but the alternatives are what? don't use usize? use T as type for the new function?

kpreid your answer help me with the doubt on why it was complaining on the MyStruct::new(10); while the try_from is another part the code. I got really confused thinking that the function signature was wrong.

Now let's go to what still are not clear to me.


Another one is when I see this types of errors.

the following other types implement trait `From<T>`:
     <i32 as From<bool>>
     <i32 as From<i8>>
     <i32 as From<i16>>
     <i32 as From<u8>>
     <i32 as From<u16>>

Does this means that I need to implement the trait for some types?


To comeback to another error, if I remove the where.

--impl<T> QuickFind<T> where T: From<usize> {
++impl<T> QuickFind<T> {

The error now is this.

the trait bound `T: TryFrom<usize>` is not satisfied
let value = T::try_from(i).unwrap();
            ^ the trait `From<usize>` is not implemented for `T`, which is required by `T: TryFrom<_>`

That's why I put the where T: From<usize> earlier

And it suggests to use this.

impl<T: std::convert::From<usize>> QuickFind<T> {

And this don't work too.


But ok let's go for what's working.

--impl<T> QuickFind<T> {
++impl<T> QuickFind<T> where T: TryFrom<usize> {

And now we got this.

error[E0277]: `<T as TryFrom<usize>>::Error` doesn't implement `Debug`
let value = T::try_from(i).unwrap();
                          ^^^^^^ `<T as TryFrom<usize>>::Error` cannot be formatted using `{:?}` because it doesn't implement `Debug`
help: the trait `Debug` is not implemented for `<T as TryFrom<usize>>::Error`
required by a bound in `Result::<T, E>::unwrap`
pub fn unwrap(self) -> T
       ------ required by a bound in this associated function
where
    E: fmt::Debug,
       ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap`
help: consider further restricting the associated type
    fn new(size: usize) -> QuickFind<T> where <T as TryFrom<usize>>::Error: Debug{
                                        +++++++++++++++++++++++++++++++++++++++++

And I don't understand almost nothing from this message.

Do I have to implement something in some type?

And why T is being casted to TryFrom<usize>>::Error

And to finalize, that's my point, I kinda get by just coping things from help messages from terminal to my code.

I can proficiently code in Typescript and GO, but I don’t know why rust messes with my mind.

Even reading the rustc --explain E0277

Where it says:

You tried to use a type which doesn't implement some trait in a place which expected that trait.
...
In order to fix this error, verify that the type you're using does implement the trait.

So lets implement debug for MyStruct...

I tried and got this error

#[derive(Debug)]
         ^^^^^ conflicting implementation for `QuickFind<_>`

I forgot about the derive =D

I know that I'm having problem understanding Rust.

But I usually don't find material explaining those silly things that my mind get hung up.

For example, I don't want to use.

fn new(size: usize) -> QuickFind<T> where <T as TryFrom<usize>>::Error: Debug {

That's so ugly to me that I want to find another way to fix those errors messages without just copying from the terminal to my code without understanding.

That's why I'm asking for recommendations on materials to read.

I never found a place that explain this.

fn new(size: usize) -> QuickFind<T> where <T as TryFrom<usize>>::Error: Debug {

Well, sorry for the long reply, I usually never post on forums to not bother people, but I spent a lot of time with that simple code that I was reconsidering my life choices as a dev :laughing: .

Thanks all for the replies.

Any web courses, books or material recommendation will be very appreciated.

ps: It compiled \o/

that's just an accidental side effect of the fact you are using Result::unwrap() inside your function, because Result::unwrap() need to print out the error as the panic message, which requires the Debug bound.

if you remove the unwrap() or replace it with similar construct, the code with TryFrom should work just fine. for example, either convert the Result to Option then unwrap, or you manually match on the Result, like this:

// convert to `Option` then unwrap
let value = T::try_from(i).ok().unwrap();
// or manually match
let value = match T::try_from(i) {
    Ok(value) => value,
    Err(_) => unreachable!(),
}

if you want to keep the Result::unwrap(), you can just add the required Debug bounds:

impl<T> QuickFind<T> where
  T: TryFrom<usize>,
  <T as TryFrom<usize>>::Error: Debug,
{
  //...
}
1 Like

This text is not an error, but more of a suggestion. It is intended to help you with the situation where you're using a value of a type that doesn't implement some trait, but you could be using some other type, like for example by changing fn new(size: usize) to fn new(size: u8) since i32 does implement From<u8>. The compiler is trying to help you navigate unfamiliar types and traits by telling you what other implementations are available rather than making you go looking in the documentation yourself. In this case, it's not relevant since you don't want to change the types involved.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.