Why does asserting on the result of Deref::deref fail with a type mismatch? - pointers

The following is the Deref example from The Rust Programming Language except I've added another assertion.
Why does the assert_eq with the deref also equal 'a'? Why do I need a * once I've manually called deref?
use std::ops::Deref;
struct DerefExample<T> {
value: T,
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x.deref()); // this is true
// assert_eq!('a', x.deref()); // this is a compile error
assert_eq!('a', *x); // this is also true
println!("ok");
}
If I uncomment the line, I get this error:
error[E0308]: mismatched types
--> src/main.rs:18:5
|
18 | assert_eq!('a', x.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected char, found &char
|
= note: expected type `char`
found type `&char`
= help: here are some functions which might fulfill your needs:
- .to_ascii_lowercase()
- .to_ascii_uppercase()
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

First, let's spell out the generic types for your specific example: 'a' is char, so we have:
impl Deref for DerefExample<char> {
type Target = char;
fn deref(&self) -> &char {
&self.value
}
}
Notably, the return type of deref is a reference to a char. Thus it shouldn't be surprising that, when you use just x.deref(), the result is a &char rather than a char. Remember, at that point deref is just another normal method — it's just implicitly invoked as part of some language-provided special syntax. *x, for example, will call deref and dereference the result, when applicable. x.char_method() and fn_taking_char(&x) will also call deref some number of times and then do something further with the result.
Why does deref return a reference to begin with, you ask? Isn't that circular? Well, no, it isn't circular: it reduces library-defined smart pointers to the built-in type &T which the compiler already knows how to dereference. By returning a reference instead of a value, you avoid a copy/move (which may not always be possible!) and allow &*x (or &x when it's coerced) to refer to the actual char that DerefExample holds rather than a temporary copy.
See also:
Why is the return type of Deref::deref itself a reference?

Related

SliceIndex trait bound unsatisfied error when trying to index into a vector in Rust

I have a struct:
pub struct SomeCollection<'a> {
items: Vec<&'a SomeValue>,
name_mapping: HashMap<&'a str, usize>,
index_mapping: HashMap<&'a str, usize>
}
impl<'a> Index for SomeCollection<'a> {
type Output = Option<&'a SomeValue>;
fn index(&self, value_name: &str) -> &Self::Output {
match self.name_mapping.get(value_name) {
Some(index) => &self.items.get(index),
None => match self.index_mapping.get(value_name) {
Some(index) => &self.items.get(index),
None => &None
}
}
}
}
When I try compiling this code I get the following error:
error[E0277]: the trait bound `&usize: std::slice::SliceIndex<[&SomeValue]>` is not satisfied
--> src\some_collection.rs:49:48
|
49 | Some(index) => &self.items.get(index),
| ^^^ slice indices are of
type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[&SomeValue]>` is not implemented for `&usize`
Rust seems to be telling me that I can't index into a vector with index, which is a usize. I'm not sure why I need to implement this trait as it should be implemented for the default vector already. Can anyone enlighten me as to the real reason I'm getting this error? There may be other errors in this code that haven't surfaced yet so please bear that in mind when answering.
Maybe the compiler error is hard to understand, but at least it is accurate. It tells you, that index is a reference &usize however a Vec can only be indexed with the value usize. So all you have to do is dereference index.
Moreover, usually indexing panics if the key/index could not be found. (That's why the standard library offers the Vec::get, and HashMap::get as separate methods alongside indexing, which do not panic but return None if the given key/index not in the collection.)
impl<'a> Index<&str> for SomeCollection<'a> {
type Output = &'a SomeValue;
fn index(&self, value_name: &str) -> &Self::Output {
match self.name_mapping.get(value_name) {
Some(index) => &self.items[*index],
None => match self.index_mapping.get(value_name) {
Some(index) => &self.items[*index],
None => panic!("Missing key: {:?}", value_name),
}
}
}
}
Rust seems to be telling me that I can't index into a vector with index, which is a usize.
No, the compiler is telling you that you can't index a vector with an &usize.
the trait `std::slice::SliceIndex<[&SomeValue]>` is not implemented for `&usize`
Simply using *index instead will fix this particular problem. However, your code has other problems as well:
The Index trait needs a type parameter, e.g. &str in this case.
The index() method can generally only return a reference to data stored in the data structure you are indexing. Your code creates a temporary Option, which is not stored in the original data, and then tries to return a reference to that. If this is what you want to do, you need to define your own method (or trait) that returns the Option by value instead.

Why is the return type of Deref::deref itself a reference?

I was reading the docs for Rust's Deref trait:
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
The type signature for the deref function seems counter-intuitive to me; why is the return type a reference? If references implement this trait so they can be dereferenced, what effect would this have at all?
The only explanation that I can come up with is that references don't implement Deref, but are considered "primitively dereferenceable". However, how would a polymorphic function which would work for any dereferenceable type, including both Deref<T> and &T, be written then?
that references don't implement Deref
You can see all the types that implement Deref, and &T is in that list:
impl<'a, T> Deref for &'a T where T: ?Sized
The non-obvious thing is that there is syntactical sugar being applied when you use the * operator with something that implements Deref. Check out this small example:
use std::ops::Deref;
fn main() {
let s: String = "hello".into();
let _: () = Deref::deref(&s);
let _: () = *s;
}
error[E0308]: mismatched types
--> src/main.rs:5:17
|
5 | let _: () = Deref::deref(&s);
| ^^^^^^^^^^^^^^^^ expected (), found &str
|
= note: expected type `()`
found type `&str`
error[E0308]: mismatched types
--> src/main.rs:6:17
|
6 | let _: () = *s;
| ^^ expected (), found str
|
= note: expected type `()`
found type `str`
The explicit call to deref returns a &str, but the operator * returns a str. It's more like you are calling *Deref::deref(&s), ignoring the implied infinite recursion (see docs).
Xirdus is correct in saying
If deref returned a value, it would either be useless because it would always move out, or have semantics that drastically differ from every other function
Although "useless" is a bit strong; it would still be useful for types that implement Copy.
See also:
Why does asserting on the result of Deref::deref fail with a type mismatch?
Note that all of the above is effectively true for Index and IndexMut as well.
The compiler knows only how to dereference &-pointers - but it also knows that types that implement Deref trait have a deref() method that can be used to get an appropriate reference to something inside given object. If you dereference an object, what you actually do is first obtain the reference and only then dereference it.
If deref() returned a value, it would either be useless because it would always move out, or have semantics that drastically differ from every other function which is not nice.

Pointer-stashing generics via `mem::transmute()`

I'm attempting to write Rust bindings for a C collection library (Judy Arrays [1]) which only provides itself room to store a pointer-width value. My company has a fair amount of existing code which uses this space to directly store non-pointer values such as pointer-width integers and small structs. I'd like my Rust bindings to allow type-safe access to such collections using generics, but am having trouble getting the pointer-stashing semantics working correctly.
The mem::transmute() function seems like one potential tool for implementing the desired behavior, but attempting to use it on an instance of a parameterized type yield a confusing-to-me compilation error.
Example code:
pub struct Example<T> {
v: usize,
t: PhantomData<T>,
}
impl<T> Example<T> {
pub fn new() -> Example<T> {
Example { v: 0, t: PhantomData }
}
pub fn insert(&mut self, val: T) {
unsafe {
self.v = mem::transmute(val);
}
}
}
Resulting error:
src/lib.rs:95:22: 95:36 error: cannot transmute to or from a type that contains type parameters in its interior [E0139]
src/lib.rs:95 self.v = mem::transmute(val);
^~~~~~~~~~~~~~
Does this mean a type consisting only of a parameter "contains type parameters in its interior" and thus transmute() just won't work here? Any suggestions of the right way to do this?
(Related question, attempting to achieve the same result, but not necessarily via mem::transmute().)
[1] I'm aware of the existing rust-judy project, but it doesn't support the pointer-stashing I want, and I'm writing these new bindings largely as a learning exercise anyway.
Instead of transmuting T to usize directly, you can transmute a &T to &usize:
pub fn insert(&mut self, val: T) {
unsafe {
let usize_ref: &usize = mem::transmute(&val);
self.v = *usize_ref;
}
}
Beware that this may read from an invalid memory location if the size of T is smaller than the size of usize or if the alignment requirements differ. This could cause a segfault. You can add an assertion to prevent this:
assert_eq!(mem::size_of::<T>(), mem::size_of::<usize>());
assert!(mem::align_of::<usize>() <= mem::align_of::<T>());

Cannot move out of borrowed content when borrowing a generic type

I have a program that more or less looks like this
struct Test<T> {
vec: Vec<T>
}
impl<T> Test<T> {
fn get_first(&self) -> &T {
&self.vec[0]
}
fn do_something_with_x(&self, x: T) {
// Irrelevant
}
}
fn main() {
let t = Test { vec: vec![1i32, 2, 3] };
let x = t.get_first();
t.do_something_with_x(*x);
}
Basically, we call a method on the struct Test that borrows some value. Then we call another method on the same struct, passing the previously obtained value.
This example works perfectly fine. Now, when we make the content of main generic, it doesn't work anymore.
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
Then I get the following error:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
I'm not completely sure why this is happening. Can someone explain to me why Test<i32> isn't borrowed when calling get_first while Test<T> is?
The short answer is that i32 implements the Copy trait, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>), then your immediate problem is fixed.
The longer answer is that Copy is a special trait which means values can be copied by simply copying bits. Types like i32 implement Copy. Types like String do not implement Copy because, for example, it requires a heap allocation. If you copied a String just by copying bits, you'd end up with two String values pointing to the same chunk of memory. That would not be good (it's unsafe!).
Therefore, giving your T a Copy bound is quite restrictive. A less restrictive bound would be T: Clone. The Clone trait is similar to Copy (in that it copies values), but it's usually done by more than just "copying bits." For example, the String type will implement Clone by creating a new heap allocation for the underlying memory.
This requires you to change how your generic_main is written:
fn generic_main<T: Clone>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x.clone());
}
Alternatively, if you don't want to have either the Clone or Copy bounds, then you could change your do_something_with_x method to take a reference to T rather than an owned T:
impl<T> Test<T> {
// other methods elided
fn do_something_with_x(&self, x: &T) {
// Irrelevant
}
}
And your generic_main stays mostly the same, except you don't dereference x:
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x);
}
You can read more about Copy in the docs. There are some nice examples, including how to implement Copy for your own types.

Why can't I reuse a funtion's borrowed pointer

I don't understand why rustc gives me this error error: use of moved value: 'f' at compile time, with the following code:
fn inner(f: &fn(&mut int)) {
let mut a = ~1;
f(a);
}
fn borrow(b: &mut int, f: &fn(&mut int)) {
f(b);
f(b); // can reuse borrowed variable
inner(f); // shouldn't f be borrowed?
// Why can't I reuse the borrowed reference to a function?
// ** error: use of moved value: `f` **
//f(b);
}
fn main() {
let mut a = ~1;
print!("{}", (*a));
borrow(a, |x: &mut int| *x+=1);
print!("{}", (*a));
}
I want to reuse the closure after I pass it as argument to another function. I am not sure if it is a copyable or a stack closure, is there a way to tell?
That snippet was for rustc 0.8. I managed to compile a different version of the code with the latest rustc (master: g67aca9c), changing the &fn(&mut int) to a plain fn(&mut int) and using normal functions instead of a closure, but how can I get this to work with a closure?
The fact of the matter is that &fn is not actually a borrowed pointer in the normal sense. It's a closure type. In master, the function types have been fixed up a lot and the syntax for such things has changed to |&mut int|—if you wanted a borrowed pointer to a function, for the present you need to type it &(fn (...)) (&fn is marked obsolete syntax for now, to help people migrating away from it, because it's a completely distinct type).
But for closures, you can then go passing them around by reference: &|&mut int|.

Resources