4

I would like to write something like the following:

pub struct Point<T> {
    pub x: T,
    pub y: T,
}

impl<T> Point<T> {
    pub fn from<U>(other: Point<U>) -> Point<T> {
        Point {
            x: other.x as T,
            y: other as T,
        }
    }
}

This is not possible:

error[E0605]: non-primitive cast: `U` as `T`
 --> src/lib.rs:9:16
  |
9 |             x: other.x as T,
  |                ^^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

Looking at How do I cast generic T to f32 if I know that it's possible?, I learnt that the From trait doesn't work for i32 to f32 conversion, which is what I wanted originally.

The simplest solution I can come up with is to write a function like:

pub fn float2_from_int2(v: Point<i32>) -> Point<f32> {
   Point::<f32>::new(v.x as f32, v.y as f32)
}

Clearly Rust has no problem casting from i32 to f32. Is there a nicer way to write this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
B_old
  • 1,141
  • 3
  • 12
  • 26
  • Note that you should take `self`, that make more sense – Stargateur Apr 26 '19 at 12:53
  • Could you elaborate on that? I don't have a `self` yet, because I just was about to create the `Point`. Hence the `from`, as a constructor so to speak. – B_old Apr 26 '19 at 12:57
  • I not advice you to implement `From` there is a reason where there is no `From for f32` implementation, maybe do this, https://play.integer32.com/?version=nightly&mode=debug&edition=2018&gist=6aea7192ed830c36aa2a53c31f219ff1, but be aware that like my exemple show, this could lead to strange behavior. – Stargateur Apr 26 '19 at 13:10

1 Answers1

3

you can use ToPrimitive trait from num
example (you can avoid Option with AsPrimitive):

pub struct Point<T> {
    pub x: T,
    pub y: T,
}

impl<T: Copy + 'static> Point<T> {
    pub fn from<U: num::cast::AsPrimitive<T>>(other: Point<U>) -> Point<T> {
        Point {
            x: other.x.as_(),
            y: other.y.as_(),
        }
    }
}

fn do_stuff() {
    let a = Point{x: 0i32, y: 0i32};
    let b = Point::<f32>::from(a);
}
Laney
  • 1,571
  • 9
  • 7
  • 1
    The methods in traits `NumCast` and `ToPrimitive` return an `Option` because it is possible that the given value cannot be represented in the target type (e.g. you cannot hold `256` in a `u8`). These are indeed safer to use, since they can avoid odd situations. `AsPrimitive` disregards this, thus behaving exactly like the `as` operator. – E_net4 Apr 26 '19 at 13:40
  • Maybe implementing the newly stabilized `TryFrom` trait would be a good way to handle the `Optional` results? – apetranzilla Apr 26 '19 at 13:48
  • How could one implement this in / as a "From" trait? Like: impl From> for Point... – Elembivios Jul 28 '23 at 09:18