Expecting and getting different types - rust

I am trying to learn rust following this https://github.com/dhole/rust-homework/tree/master/hw03, which follows this https://rust-unofficial.github.io/too-many-lists/second-option.html, and when I try to do this:
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> {
elem: T,
left: Link<T>,
right: Link<T>,
}
pub struct BST<T: std::cmp::PartialOrd> {
root: Link<T>,
}
impl<T: std::cmp::PartialOrd> BST<T> {
pub fn new() -> Self {
BST { root: None }
}
pub fn insert(&mut self, elem: T) -> bool {
self.root.insert(elem)
}
}
trait InsertSearch<T: std::cmp::PartialOrd> {
fn insert(&mut self, elem: T) -> bool;
}
impl<T: std::cmp::PartialOrd> InsertSearch<T> for Link<T> {
fn insert(&mut self, elem: T) -> bool {
true
}
}
I get the following 2 erros:
error[E0308]: mismatched types
--> src\second.rs:35:34
|
23 | impl<T: std::cmp::PartialOrd> BST<T> {
| - this type parameter
...
35 | self.root.insert(elem)
| ^^^^ expected struct `Box`, found type parameter `T`
|
= note: expected struct `Box<second::Node<T>>`
found type parameter `T`
Why is it expecting a Box, when I am calling Option<Box<Node<T>>>::insert(T)?
error[E0308]: mismatched types
--> src\second.rs:35:17
|
28 | pub fn insert(&mut self, elem: T) -> bool {
| ---- expected `bool` because of return type
...
35 | self.root.insert(elem)
| ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found mutable reference
|
= note: expected type `bool`
found mutable reference `&mut Box<second::Node<T>>`
And this one really confuses me. Why is it getting &mut Box<second::Node<T>>, when the return type of the insert function is bool? What am I calling then?

Both errors have the same reason: you're not calling the insert() function you defined. You're calling another function.
Remember Link is actually Option<_> (Option<Box<Node<T>>>, to be precise). And Option has an insert() method. And it takes T (not your T, the Option's T, which is Box<Node<T>> in this case) and produces &mut T (&mut Box<Node<T>>). And when you call some method, you always call an inherent method if one exists; only if there is no inherent method with that name you call a trait method, but in this case there is.
The solution can be to use Universal Function Call Syntax - <Link<T> as InsertSearch<T>>::insert(&mut self.root, elem), but I would recommend just making Link a newtype struct instead of a type alias. That is,
struct Link<T>(Box<Node<T>>);
This way, you can define an inherent insert() method, and you don't inherit Option's methods.

Related

Generic type parameters when calling non-generic trait methods

I have a trait Command<P> with two functions like this:
trait Client<P> {}
trait Command<P> {
fn help(&self) -> String;
fn exec(&self, client: &dyn Client<P>) -> String;
}
struct ListCommand {}
impl<P> Command<P> for ListCommand {
fn help(&self) -> String {
return "This is helptext".to_string();
}
fn exec(&self, client: &dyn Client<P>) -> String {
self.help()
}
}
fn main() {
println!("Hello!");
}
Rust complains I can't call self.help() in exec() with the following error:
error[E0282]: type annotations needed
--> src\main.rs:15:14
|
15 | self.help()
| ^^^^ cannot infer type for type parameter `P` declared on the trait `Command`
Playground
How can I specify the type annotations for calling methods on Self?
I can think of three ways:
Command::<P>::help(self)
<Self as Command<P>>::help(self) (or ListCommand instead of Self)
(self as &dyn Command<P>).help() (I wonder if there's a variation of this that doesn't involve dyn.)

Rust deref coersion doesn't work for nested types

I'm running into an issue where the compiler seems unable to coerce the desired type by recursive deref-coersion. I have the following code:
use std::ops::Deref;
struct MyStruct<T> {
data: T
}
impl<T> Deref for MyStruct<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
pub trait MyTrait {
fn bar(&self);
}
impl<T> MyTrait for MyStruct<T> {
fn bar(&self) {}
}
fn foo<T: MyTrait>(arg: T) {
//
}
fn main() {
let data = Box::new(MyStruct { data: 42 });
foo(&data);
}
And I get the following error:
error[E0277]: the trait bound `&Box<MyStruct<{integer}>>: MyTrait` is not satisfied
--> src\bin\main.rs:36:9
|
36 | foo(&data);
| ^^^^^ the trait `MyTrait` is not implemented for `&Box<MyStruct<{integer}>>`
|
note: required by a bound in `foo`
--> src\bin\main.rs:30:11
|
30 | fn foo<T: MyTrait>(arg: T) {
| ^^^^^^^ required by this bound in `foo`
My expectation is that the compiler would be able to recursively deref Box<MyStruct> until it encountered a type that satisfied the trait requirement (MyTrait) for the argument.
How might I be able to achieve this without modifying the calling syntax of foo(&data)?

My T generic does implement the conditions on where, but I can't use it

struct Response {}
struct PlayResponse(Response);
struct DescribeResponse(Response);
impl From<Response> for PlayResponse {
fn from(response: Response) -> Self {
PlayResponse(response)
}
}
enum RtspState {
Init,
Playing,
}
struct RtspMachine {
state: RtspState
}
pub trait OnEvent<T> {
fn on_event(&mut self, event: &T) -> std::result::Result<(), ()>;
}
impl OnEvent<PlayResponse> for RtspMachine {
fn on_event(&mut self, event: &PlayResponse) -> std::result::Result<(), ()> {
self.state = RtspState::Playing;
Ok(())
}
}
fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
let mut rtsp_machine = RtspMachine{state: RtspState::Init};
rtsp_machine.on_event(&T::from(Response{}));
rtsp_machine.on_event(&PlayResponse::from(Response{}));
}
On the do_something above, we require where RtspMachine: OnEvent<T>, T: From<Response>.
Note that RtspMachine: OnEvent<PlayResponse> and PlayResponse: From<Response>. I should be able to do rtsp_machine.on_event(&PlayResponse::from(Response{}));, but it only works for the version with T.:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:36:27
|
33 | fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
| - this type parameter
...
36 | rtsp_machine.on_event(&PlayResponse::from(Response{}));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `PlayResponse`
|
= note: expected reference `&T`
found reference `&PlayResponse`
Rust playground
I know that
fn do_something<T>() where
RtspMachine: OnEvent<T> + OnEvent<PlayResponse>,
T: From<Response>
would work but I have lots of T that I wanted to use the specific type instead of generic T, so I can't just put them all on the where like that.
This is a known problem with the compiler's method resolution in the presence of trait bounds (#24066, #38071). Changing your method call
rtsp_machine.on_event(&PlayResponse::from(Response{}));
to the explicit function call form
OnEvent::<PlayResponse>::on_event(
&mut rtsp_machine, &PlayResponse::from(Response{}));
will allow the code to compile. Apparently, in the version that doesn't work, method resolution is looking only at the OnEvent<T> trait that's mentioned in where, even though OnEvent<PlayResponse> also exists.
I don't know if there's a more elegant solution, but perhaps the above will be adequate for your problem — at least it means the extra syntax is local to the call site.

What happens when a Rust struct contains a lifetimed trait?

Ok, so I'm a total Rust newbie, and I'm experimenting with Rocket. That web framework passes a Form<MyStruct>, and I want to transfer that MyStruct into my own custom struct.
struct Consumer<T> {
d: T,
}
impl<T> Consumer<T> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner() }
}
}
That doesn't work of course, I get:
the trait `rocket::request::FromForm<'_>` is not implemented for `T`
Next attempt:
impl<T> Consumer<T> where T: FromForm {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
Uh oh:
impl<T> Consumer<T> where T: FromForm {
^^^^^^^^ expected lifetime parameter
So now I find myself completely unable to fix this! The best I can come up with is:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
But that results in this error:
51 | fn new(form: Form<T>) -> Self {
| _________^
52 | | Consumer { d: form.into_inner }
53 | | }
| |_________^ lifetime mismatch
= note: expected type `rocket::request::FromForm<'_>`
found type `rocket::request::FromForm<'f>`
Verifiable example: https://hastebin.com/eqihaqodux.makefile
Form also has a lifetime parameter. If you tie it to the lifetime of FromForm, then you'll move forward a little:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}
As a general rule, if you return an object that depends on data in another object, then you'll need to link their lifetimes together like this.
At this point, you'll see another error, which conveniently gives you all the information you need to fix it:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:50:17
|
48 | impl<'f, T> Consumer<T> where T: FromForm<'f> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
49 | fn new(form: Form<'f, T>) -> Self {
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/main.rs:50:17
|
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
The into_inner method on Form requires that it's type parameter T has the 'static lifetime, and the error message suggests adding this constraint.
With these changes, it will compile:
impl<'f, T: 'static> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}

"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