I found myself in a situation where my generic object needs to call an extern function of another library that returns Vec<usize> but I want to store it into Vec<T>. Clearly I cannot do that. Example:
pub struct X<T> {
x: Vec<T>,
}
fn vec_make() -> Vec<usize> {
let x = vec![2; 20];
x
}
impl<T> X <T>
where
T: From<u8> + Clone,
{
pub fn new() -> Self {
X {
x: vec![T::from(1); 20],
}
}
pub fn set(mut self) {
self.x = vec_make();
}
}
fn main() {
let mut b = X::<i32>::new();
b.set()
}
////////////////////////////////////////
error[E0308]: mismatched types
--> src/main.rs:20:18
|
20 | self.x = vec_make();
| ^^^^^^^^^^ expected type parameter, found usize
|
= note: expected type `std::vec::Vec<T>`
found type `std::vec::Vec<usize>`
What would be the most elegant way to convert the Vec<usize> returned by vec_make() into T, as set by object constructor?
use core::fmt::Debug;
pub struct X<T> {
x: Vec<T>,
}
fn vec_make() -> Vec<usize> {
let x = vec![2; 20];
x
}
impl<T> X<T>
where
T: From<u8> + Clone + Debug,
usize: Into<T>,
{
pub fn new(c: Vec<T>) -> Self {
X { x: c }
}
pub fn set(mut self) {
self.x.clear();
self.x.extend(vec_make().into_iter().map(usize::into));
println!("{:?}", self.x);
}
}
fn main() {
let xx = vec![22; 5]; // works
//let xx = vec![2i32; 5]; // not
let b = X::new(xx);
b.set()
}
//--------------------------
// for let xx = vec![2i32; 5]
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `i32: std::convert::From<usize>` is not satisfied
--> src/main.rs:32:13
|
32 | let b = X::new(xx);
| ^^^^^^ the trait `std::convert::From<usize>` is not implemented for `i32
Or I did not understand the point you were trying to make
It is because you bound your T to From<u8> instead of From<usize>. Changing to the second one would be the best option, but if you cannot do this, you may also change mapping to:
self.x.extend(vec_make().into_iter).map(|i| (i as u8).into());
use core::fmt::Debug;
pub struct X<T> {
x: Vec<T>,
}
fn vec_make() -> Vec<usize> {
let x = vec![2; 20];
x
}
impl<T> X<T>
where
T: From<usize> + Clone + Debug,
usize: Into<T>,
{
pub fn new(c: Vec<T>) -> Self {
X { x: c }
}
pub fn set(mut self) {
self.x.clear();
self.x.extend(vec_make().into_iter().map(usize::into));
//self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
println!("{:?}", self.x);
}
}
fn main() {
//let xx = vec![22; 5]; // works
let xx = vec![2i32; 5]; // not
let b = X::new(xx);
b.set()
}
////and again
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `i32: std::convert::From<usize>` is not satisfied
--> src/main.rs:34:13
|
34 | let b = X::new(xx);
| ^^^^^^ the trait `std::convert::From<usize>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as std::convert::From<bool>>
<i32 as std::convert::From<i16>>
<i32 as std::convert::From<i8>>
<i32 as std::convert::From<std::num::NonZeroI32>>
and 2 others
note: required by `X::<T>::new`
--> src/main.rs:19:5
|
19 | pub fn new(c: Vec<T>) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0599]: no method named `set` found for type `X<i32>` in the current scope
--> src/main.rs:35:7
|
3 | pub struct X<T> {
| --------------- method `set` not found for this
...
35 | b.set()
| ^^^
|
= note: the method `set` exists but the following trait bounds were not satisfied:
`i32 : std::convert::From<usize>`
`usize : std::convert::Into<i32>`
OR if I revert back to the original setup:
use core::fmt::Debug;
pub struct X<T> {
x: Vec<T>,
}
fn vec_make() -> Vec<usize> {
let x = vec![2; 20];
x
}
impl<T> X<T>
where
T: From<usize> + Clone + Debug,
usize: Into<T>,
{
pub fn new() -> Self {
X { x: vec![T::from(1);8] }
}
pub fn set(mut self) {
self.x.clear();
self.x.extend(vec_make().into_iter().map(usize::into));
//self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
println!("{:?}", self.x);
}
}
fn main() {
let b = X::<i32>::new();
b.set()
}
//////////7----------------------------
Compiling playground v0.0.1 (/playground)
error[E0599]: no function or associated item named `new` found for type `X<i32>` in the current scope
--> src/main.rs:34:23
|
3 | pub struct X<T> {
| --------------- function or associated item `new` not found for this
...
34 | let b = X::<i32>::new();
| ^^^ function or associated item not found in `X<i32>`
|
= note: the method `new` exists but the following trait bounds were not satisfied:
`i32 : std::convert::From<usize>`
`usize : std::convert::Into<i32>`
UPDATE:
but it makes sense If I'm on a 64 bit machine and want to downsize to 32 than my Vector will break... (in case my vec is too big for 32 bit machine)
Going from a signed to an unsigned type is not supported with From only with TryFrom since you have to decide what should happen when the number was negative.
This is part of the problem - the other part is that u32 can hold twice as many positive values as i32 (since it doesn't need the sign bit). So even on a 32-bit platform, it would only be completely safe to convert usize to u32, not i32.
I think you have it the other way around - the attempted conversion is from an unsigned type (usize) into a signed type (i32).
The advice to use TryFrom is sound, though!
@mrmxs Changing the code you posted to use TryFrom / TryInto instead of From/Into makes it work.
You need to have some kind of error handling, to specify what happens if given values that can't be converted - what you want to do probably depends on your exact use case. In the following modified code, I just have it panicking:
use core::{convert::TryInto, fmt::Debug};
pub struct X<T> {
x: Vec<T>,
}
fn vec_make() -> Vec<usize> {
let x = vec![2; 20];
x
}
impl<T> X<T>
where
T: Clone + Debug,
usize: TryInto<T>,
// require the error type be Debug so we can use `expect`
<usize as TryInto<T>>::Error: Debug,
{
pub fn new() -> Self {
X {
x: vec![1.try_into().expect("expected conversion to succeed"); 8],
}
}
pub fn set(mut self) {
self.x.clear();
self.x.extend(vec_make().into_iter().map(|usize_value| {
usize_value
.try_into()
.expect("expected conversion to succeed")
}));
//self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
println!("{:?}", self.x);
}
}
fn main() {
let b = X::<i32>::new();
b.set()
}