As per the question, Let's say I have a following code:
struct Test {
x: i32
}
fn main() {
let test1 = Test { x: 32 }; // type inference by vscode: Test
let test2 = &test1 // type inference by vscode: &Test
let test3 = &test2 // type inference by vscode: &&Test
let explicit_ref: &Test = &test3; // This should give an error but works as I haven't implemented
//Deref trait.
}
Did I miss anything or did I misunderstand automatic dereferencing and deref coercion?
Deref Coercions
If you have a type U, and it implements Deref<Target=T>, values of &U will automatically coerce to a &T.
Automating Referencing/Dereferencing
Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:
p1.distance(&p2);
(&p1).distance(&p2);
This automatic referencing behavior works because methods have a clear receiver—the type of self. Given the receiver and name of a method, Rust can figure out definitively whether the method is reading (&self), mutating (&mut self), or consuming (self).
Sources
You can read about Deref coercions here.
You can read about automatic referencing/referencing here.
Related
I don't understand something about the feature that makes it possible to coerce a tuple struct to a function as in:
struct MyType(u8);
let optional_mytype: Option<MyType> = Some(12).map(MyType);
// ^^^^^^ here, MyType is treated as a function
In the example above, no lifetimes are involved: everything is easy. However, when the structure has a generic lifetime bound, I'm having troubles defining the exact signature of the function it would coerce to.
Here's a MRE of something I've attempted to do, and that doesn't work (sandbox link):
struct MyStruct<'a>(&'a ());
// This looks, to me, like the signature the "constructor" should have
type MyStructConstructor = for<'a> fn(&'a ()) -> MyStruct<'a>;
/// Coercion problem here
fn some_code() {
let mut constructor: MyStructConstructor = MyStruct;
}
and the error given by the type-checker:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:7:48
|
7 | let mut constructor: MyStructConstructor = MyStruct;
| ^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a ()) -> MyStruct<'a>`
found fn pointer `fn(&()) -> MyStruct<'_>`
And I honestly don't understand why my constructor type alias isn't valid, and why the type suggested by the error message is much more lax than it should be. I mean, the lifetime <'a> of my structure should be exactly equal to that of the unit reference that is contained by the structure, not a random one.
Here's a more concrete (still minimal) example of what I'm actually trying to do, if having context helps you.
Thanks in advance
In fact, the error message might be a bit misleading. '_ does not mean any lifetime goes, it just means a lifetime I haven't named explicitly, just as writing &() (which is the same as &'_ ()). Rust does that because that's not the issue.
To understand, let's actually annotate implicit generic lifetimes in your code:
fn some_code() {
let constructor: MyStructConstructor = MyStruct<'_>;
}
Notice how something is wrong? On the right hand side, you have something whose type is generic over a lifetime. On the left hand side, you don't.
In fact, a more appropriate constructor signature for MyStruct would be
struct MyStruct<'a>(&'a ());
type MyStructConstructor<'a> = fn(&'a ()) -> MyStruct<'a>;
fn some_code() {
let constructor: MyStructConstructor = MyStruct;
}
leaving the lifetime implicit — see the playground.
This compiles.
So now you may understand why MyStructConstructor was more generic than MyStruct: because for MyStruct, you have to specify a lifetime to begin with, that is, the actual type is, for a given 'a, MyStruct<'a>. Then, with that constructor, you are only capable of building objects of type MyStruct<'a>, given &'a (). On the other hand, with MyStructConstructor, given a reference to a () with any lifetime, you would be able to build a MyStruct of the same lifetime, which is more general.
Is it possible to convert type T into generic type without use of into() ?
struct MyType<T>(T);
impl<T> From<T> for MyType<T> {
fn from(v: T) -> Self {
Self(v)
}
}
#[allow(unused_variables)]
fn main() {
let test1 = MyType(12);
//let test2: MyType<i32> = 12; // why is this not working
let test3: MyType<i32> = 12.into();
let test4 = MyType::from(12);
}
fn test_fnc_1() -> MyType<i32> {
12 // not working
12.into()
}
I want to do "test2", but this is not possible. I have to do "test3".
Another sample, I thought it is somehow possible, is in test_func_1.
Playground
The reason it is not possible is because the cost of converting a value into your time can be arbitrarily large. Implicit conversion would hide this cost, which is not desirable for system language.
As far as I know there are no plans to add implicit conversion into Rust.
Rust is fairly reserved about implicit conversions. In Type Coercions in the Rust Reference you can see most of them are dictated by the compiler, with Deref being the only user-defined conversion that may be done implicitly. An exception of course is the ? operator which does invoke a From conversion.
There is no implicit From conversion that is called when passing arguments, returning a value, or assigning to a variable. You will have to use .into() or T::from().
What you're looking for is implicit type conversion, which isn't possible in Rust. As you've seen, you have to explicitly construct types at some point (i.e. MyType(...) in your example), and that can be done either directly or with a function call.
There are some special cases where implicit coercion occurs, but these are generally only when dealing with references or traits, not concrete value types.
An iterator can be transformed to a collection using the Iterator trait's collect method if the collection implements FromIterator.
let vec = (0..10).collect::<Vec<_>>();
let devec = (0..10).collect::<VecDeque<_>>();
Vec and VecDeque implement FromIterator trait.
The implementation of Iterator::collect method is:
fn collect<B: FromIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
FromIterator::from_iter(self)
}
How does Rust understand to call from_iter method of Vec or VecDeque from FromIterator::from_iter(self)?
When the FromIterator trait has an implementor, it has the form:
impl<T> FromIterator for Vec<T> {
fn from_iter<I>(iter: I) -> Vec<T> { /* ... */ }
}
It returns the concrete type Self; that is the generic parameter B in the collect code.
When you type collect::<Vec<_>>(), you say that B is Vec<_> and therefore, that Vec<_>::from_iter() must be called.
The implementation of collect could have been written: <B as FromIterator>::from_iter(self), but it is more verbose.
Let's look at the definition of the FromIterator trait:
pub trait FromIterator<A>: Sized {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}
From how FromIterator::from_iter() is used in the implementation of the collect() method, Rust knows that the call to FromIterator::from_iter() takes the iterator self as parameter, and returns an object of type B. This information is matched against the definition of the from_iter() method, so Rust can conclude that the Self type of the FromIterator trait implementation must be B, and that the type A must be the item type of the iterator. The Self type of the FromIterator trait is precisely the type Rust needs to call from_iter() for.
The details of how type inference works are complex. Rust uses a variant of the Hindley-Milner type inference algorithm. You can find some further information in this document from the rustc guide.
Roughly, Rust uses all information it has about unknown types as constraints and iteratively refines its knowledge about generic types, until only a single type for each unknown type remains, or some type remains ambiguous. In the former case, type inference was successful and all types have been inferred, and in the latter case, Rust will throw an error stating that it needs further type annotations.
I noticed that Box<T> implements everything that T implements and can be used transparently. For Example:
let mut x: Box<Vec<u8>> = Box::new(Vec::new());
x.push(5);
I would like to be able to do the same.
This is one use case:
Imagine I'm writing functions that operate using an axis X and an axis Y. I'm using values to change those axis that are of type numbers but belongs only to one or the other axis.
I would like my compiler to fail if I attempt to do operations with values that doesn't belong to the good axis.
Example:
let x = AxisX(5);
let y = AxisY(3);
let result = x + y; // error: incompatible types
I can do this by making a struct that will wrap the numbers:
struct AxisX(i32);
struct AxisY(i32);
But that won't give me access to all the methods that i32 provides like abs(). Example:
x.abs() + 3 // error: abs() does not exist
// ...maybe another error because I don't implement the addition...
Another possible use case:
You can appropriate yourself a struct of another library and implement or derive anything more you would want. For example: a struct that doesn't derive Debug could be wrapped and add the implementation for Debug.
You are looking for std::ops::Deref:
In addition to being used for explicit dereferencing operations with the (unary) * operator in immutable contexts, Deref is also used implicitly by the compiler in many circumstances. This mechanism is called 'Deref coercion'. In mutable contexts, DerefMut is used.
Further:
If T implements Deref<Target = U>, and x is a value of type T, then:
In immutable contexts, *x on non-pointer types is equivalent to *Deref::deref(&x).
Values of type &T are coerced to values of type &U
T implicitly implements all the (immutable) methods of the type U.
For more details, visit the chapter in The Rust Programming Language as well as the reference sections on the dereference operator, method resolution and type coercions.
By implementing Deref it will work:
impl Deref for AxisX {
type Target = i32;
fn deref(&self) -> &i32 {
&self.0
}
}
x.abs() + 3
You can see this in action on the Playground.
However, if you call functions from your underlying type (i32 in this case), the return type will remain the underlying type. Therefore
assert_eq!(AxisX(10).abs() + AxisY(20).abs(), 30);
will pass. To solve this, you may overwrite some of those methods you need:
impl AxisX {
pub fn abs(&self) -> Self {
// *self gets you `AxisX`
// **self dereferences to i32
AxisX((**self).abs())
}
}
With this, the above code fails. Take a look at it in action.
I'm trying to make a simple utility function that reads multiple elements from stdin and puts them in collection and returns it. However I'm stuck at this point. The compiler says missing associated type Err value. How do I make it work, while keeping it generic as possible?
While this function seems useless, it's for learning the language and its type system.
use std::io::{ stdin };
use std::str::FromStr;
use std::io::Read;
use std::iter::FromIterator;
pub fn read_all<C>() -> C
where C: FromIterator<FromStr<Err>>
{
let mut buff = String::new();
stdin().read_to_string(&mut buff).expect("read_to_string error");
buff.split_whitespace()
.filter_map(|w| w.parse().ok())
.collect()
}
Usage example:
let v: Vec<i32> = read_all();
Working code
The only thing you need to change to your code in order to make it compile is the type signature of the function:
pub fn read_all<C, F>() -> C
where F: FromStr,
C: FromIterator<F>
Explanation
Your code is almost correct, but there is a problem:
FromIterator<T> is a trait, but T is a type.
You use FromStr in the place of T, but FromStr is a trait, not a type.
To solve this, you need to get a type that implements FromStr. You can do this by adding a type parameter F to the function and constraining it with where F: FromStr. Then you can write FromIterator<F>.
A note on associated types
Besides the issue of using a trait instead of a type, typing FromStr<Err> is wrong syntax. While in this case it is not necessary to specify the type of Err in the FromStr trait, you could do it as shown below:
pub fn read_all<C, F, E>() -> C
where F: FromStr<Err=E>,
C: FromIterator<F>
As you can see, instead of writing FromStr<E> we need to write FromStr<Err=E>. That is, you need to explicitly type the name of the associated type you are referring to.
A note on types vs traits
Usually traits cannot be treated as types. However, there are exceptions to this rule, as illustrated by the example below:
use std::fmt::Display;
pub fn print_box(thing: Box<Display>) {
println!("{}", thing)
}
fn main() { print_box(Box::new(42)); }
Here, you would expect T in Box<T> to be a type, but the Display trait is supplied instead. However, the compiler does not reject the program. The type checker sees Display as an unsized type. That is, the type of an object with a size unknown at compile time (because it could be any type implementing Display). When T in Box<T> is a trait, the resulting type is usually referred to as a trait object. It is impossible to cover this topic in depth here, but the links I refer to are a good starting point in case you want to know more.