Get value in enum variants - rust

I am trying to get the inner values of an enum with many newtypes, like so (only two to simplify):
enum NewType {
Integer(i32),
Null,
}
impl From<i32> for NewType {
fn from(int: i32) -> Self {
Self::Integer(int)
}
}
impl NewType {
fn into_inner<T>(&self) -> Option<T>
where
T: Into<NewType>,
{
match self {
NewType::Integer(v) => Some(*v),
NewType::Null => None,
}
}
}
But I get:
error[E0308]: mismatched types
--> src/main.rs:32:41
|
27 | fn into_inner<T>(&self) -> Option<T>
| - this type parameter
...
32 | NewType::Integer(v) => Some(*v),
| ^^ expected type parameter `T`, found `i32`
|
= note: expected type parameter `T`
found type `i32`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `testrs` due to previous error
And when trying:
impl<T> From<NewType> for T {
fn from(new_value: NewType) -> Option<T>
where
T: Into<NewType>,
{
match new_value {
NewType::Integer(v) => Some(v),
NewType::Null => None,
}
}
}
I get:
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`NewType`)
--> src/main.rs:14:6
|
14 | impl<T> From<NewType> for T {
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`NewType`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
For more information about this error, try `rustc --explain E0210`.
error: could not compile `testrs` due to previous error
What would be the best way to get these inner values in Rust?

The issue is that rust has no idea how to produce T since you don't tell it how to act. The current implementation always returns a Option<i32> which does not line up with the function signature. You have the Into<NewType> trait bound, but you never make use of this trait.
It seems like you actually want to reverse the trait bound so i32 is turned into T.
impl NewType {
fn into_inner<T>(&self) -> Option<T>
where i32: Into<T>,
{
match self {
NewType::Integer(v) => Some((*v).into()),
NewType::Null => None,
}
}
}

Related

How to implement a trait on `{integer}` type in Rust

Is there a way to implement a trait for {integer} type (or all integer types). Because (as a minimal example):
pub trait X {
fn y();
}
impl<T> X for T {
fn y() {
println!("called");
}
}
fn main() {
(32).y();
}
gives an error:
error[E0689]: can't call method `y` on ambiguous numeric type `{integer}`
--> src/main.rs:12:10
|
12 | (32).y();
| ^
|
help: you must specify a concrete type for this numeric value, like `i32`
|
12 | (32_i32).y();
| ~~~~~~
For more information about this error, try `rustc --explain E0689`.
Is there a way to implement trait X for any integer type so that it can be used on any integer (even the ambiguous {integer} type)? Because if the implementation for all integer types, is the same why care about the exact type?
It is possible to bound type T by num_traits::PrimInt like this:
use num_traits::PrimInt;
trait Trait {
fn y(self) -> Self;
}
impl<T: PrimInt> Trait for T {
fn y(self) -> Self {
println!("called");
return self;
}
}
fn main() {
let x = 32;
println!("{}", x.y());
}

expected trait object `dyn Responsability`, found type parameter `T`

I am trying to implement a responsability chain in Rust:
link to playground
use std::error::Error;
struct Query {
query: String,
}
struct Response {
response: u64,
}
trait Responsability {
fn take(&self, iterator: std::slice::Iter<Box<dyn Responsability>>, query: Query) -> Result<Response, Box<dyn Error>>;
}
struct ResponsabilityChain<T: Responsability> {
responsabilities: Vec<Box<T>>,
}
impl<T: Responsability> ResponsabilityChain<T>
where
T: Responsability,
{
pub fn new(responsabilities: Vec<T>) -> Self {
let responsabilities = responsabilities.into_iter()
.map(|elt| Box::new(elt))
.collect();
Self { responsabilities }
}
pub fn launch(&self, query: Query) -> Result<Response, Box<dyn Error>> {
let iterator = self.responsabilities.iter();
let responsability = iterator.next().unwrap();
responsability.take(iterator, query)
}
}
fn main() {
println!("Hello, world!");
}
The infamous message is:
Compiling playground v0.0.1 (/playground) error[E0308]: mismatched
types --> src/main.rs:35:29 | 19 | impl<T: Responsability>
ResponsabilityChain | - this type parameter ... 35 |
responsability.take(iterator, query) |
^^^^^^^^ expected trait object dyn Responsability, found type
parameter T | = note: expected struct std::slice::Iter<'_, Box<(dyn Responsability + 'static)>>
found struct std::slice::Iter<'_, Box<T>> = help: type parameters must be constrained to match other types = note:
for more information, visit
https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
For more information about this error, try rustc --explain E0308.
error: could not compile playground due to previous error
I do not understand why the compiler complains expecting Box<dyn Responsability> while having Box<T> since I specify T: Responsability. What do I do wrong?
dyn I and <T> where T: I are different types in Rust, so the compiler complains since there's no implicit conversion.
T is a concrete type determined at compile time. dyn I it is a "trait object", it is dynamic, and concrete type is unknown, but sort of carried within.
A good video on the topic.
Conversion from <T> where T: I to dyn I is not free, it has a runtime cost, so has to be explicit with the Rust's philosophy.
The code could be fixed by using Vec<Box<dyn Responsability>> in all places. It will also allow you passing arbitrary types to new(), which is probably what you want, because Vec<T> has to contain objects of the same type (remember that this type is determined at compile time).

Type inference picks the wrong supertrait

This code:
trait Foo: PartialOrd + PartialOrd<<Self as Foo>::A> {
type A;
}
trait Bar {
type B: Foo;
fn bar(&self) -> Self::B;
}
fn baz<T: Bar>(x: T, y: T) -> bool {
x.bar() < y.bar()
}
fails to compile with this error:
error[E0308]: mismatched types
--> src/lib.rs:12:15
|
12 | x.bar() < y.bar()
| ^^^^^^^ expected Foo::A, found Bar::B
|
= note: expected associated type `<<T as Bar>::B as Foo>::A`
found associated type `<T as Bar>::B`
which seems to imply that type inference is trying to call the B: PartialOrd<B::A> impl instead of the B: PartialOrd<B> impl which is also available.
Is this a bug or just an (intentional/unintentional) limitation of Rust's type inference?
Is there a better workaround than this:
<T::B as PartialOrd>::partial_cmp(&x.bar(), &y.bar()) == Some(Ordering::Less)

Why use Self instead of the type's name in a concrete implementation?

The documentation for Add gives the following example:
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
Why did the author of the docs use Self here, instead of mentioning Point by name? Is there a technical difference, or is it purely for style points?
There are two main reasons:
flexibility. If you decide to change the name of your type, it's one less place to update.
conciseness. Self is shorter than MyType or SomeOtherType and especially ThisTypeWithGenerics<'a, 'b, A, String>.
Is there a technical difference
Yes and no, depending on how you look at it. Self is the type that has been "completely filled in" with regards to generics. This is relevant in cases like this:
struct Container<T>(T);
impl<T> Container<T> {
fn replace<U>(self, new: U) -> Self {
Container(new)
}
}
error[E0308]: mismatched types
--> src/lib.rs:5:19
|
3 | impl<T> Container<T> {
| - expected type parameter
4 | fn replace<U>(self, new: U) -> Self {
| - found type parameter
5 | Container(new)
| ^^^ expected type parameter `T`, found type parameter `U`
|
= note: expected type parameter `T`
found type parameter `U`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
Self is the complete type Container<T>, not the type constructor Container. This can cause hard-to-understand errors.
See also:
What's the difference between self and Self?

"expected type parameter, found struct" when implementing trait

I am trying to create a trait for a directed graph structure and provide one very basic implementatio, but am running into compiler errors:
pub trait DiGraph<'a> {
type N;
fn nodes<T>(&'a self) -> T where T: Iterator<Item=&'a Self::N>;
fn pre<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
fn succ<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
}
struct SimpleNode {
pre: Vec<usize>,
succ: Vec<usize>,
}
pub struct SimpleDiGraph {
pub nodes: Vec<SimpleNode>
}
impl<'a> DiGraph<'a> for SimpleDiGraph {
type N = usize;
fn nodes<T=std::ops::Range<usize>>(&'a self) -> T {
return std::ops::Range { start: 0, end: self.nodes.len() };
}
fn pre<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
return self.nodes[node].pre.iter();
}
fn succ<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
return self.nodes[node].succ.iter();
}
}
The error messages are:
error[E0308]: mismatched types
--> digraph.rs:21:16
|
21 | return std::ops::Range { start: 0, end: self.nodes.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::ops::Range`
|
= note: expected type `T`
= note: found type `std::ops::Range<usize>`
error[E0308]: mismatched types
--> digraph.rs:24:16
|
24 | return self.nodes[node].pre.iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note: found type `std::slice::Iter<'_, usize>`
error[E0308]: mismatched types
--> digraph.rs:27:16
|
27 | return self.nodes[node].succ.iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note: found type `std::slice::Iter<'_, usize>`
The error message is somewhat confusing to me - why would a type parameter be expected as return value? Is this simply a type mismatch (e.g. due to lifetimes) with a misleading error message?
<T=std::ops::Range<usize>> doesn't force T to be std::ops::Range<usize>, it just causes it to default to that if it doesn't know what else to use.
If you only ever want to return a Range<usize>, then use Range<usize> as the return type; there's no reason to have a generic parameter at all. What your code is effectively saying now is something like this:
"You can pick any return type you want! If you don't care, I'll return a range<usize>."
"I'd like you to return a String, please."
"TOUGH you're getting a range<usize>!"
"... but you said..."
"I lied! MUAHAHAHAHAHA!"
If you actually want the caller to choose the return type, then you need to be prepared to return any T... which is almost impossible, since it could be anything from () to String to an OpenGL render context.
In that case, what you actually want to do is constrain T to some trait that requires types implement some sort of construction function. Default is an example of one.
Edit: Just to doubly clarify: you don't get to pick the types used in generic parameters, your caller does.
I didn't notice until just now that you're using different definitions in the trait and the implementation (don't do that). I assume that what you're really trying to do is say "this method returns something that's usable as an Iterator, but each impl can pick a different type." You cannot do this with generics.
What you want is an associated type on the trait, like so:
pub trait DiGraph<'a> {
type Nodes;
fn nodes(&'a self) -> Self::Nodes;
}
pub struct SimpleNode {
pre: Vec<usize>,
succ: Vec<usize>,
}
pub struct SimpleDiGraph {
pub nodes: Vec<SimpleNode>
}
impl<'a> DiGraph<'a> for SimpleDiGraph {
type Nodes = std::ops::Range<usize>;
fn nodes(&'a self) -> Self::Nodes {
return std::ops::Range { start: 0, end: self.nodes.len() };
}
}

Resources