What code will actually be generated when a generic struct implements `Deref`? - rust

I can't really understand the dereference here. The type of foo is TattleTell<&str>. The method len() is from foo.value, i.e. foo.value.len(). So why deref of TattleTell is invoked?
use std::ops::Deref;
struct TattleTell<T> {
value: T,
}
impl<T> Deref for TattleTell<T> {
type Target = T;
fn deref(&self) -> &T {
println!("{} was used!", std::any::type_name::<T>());
&self.value
}
}
fn main() {
let foo = TattleTell {
value: "secret message",
};
// dereference occurs here immediately
// after foo is auto-referenced for the
// function `len`
println!("{}", foo.len());
}

I won't fully describe Rust's auto-dereferencing rules because they are covered in other answers. For example, here.
In your case, you are trying to call a method, len, on a TattleTell<&'static str>. This type doesn't directly have that method so, using the rules in that other answer, Rust goes looking for it, using the following steps:
Check if the method exists on &TattleTell<&'static str>. It doesn't.
Check if the method exists on *&TattleTell<&'static str>. Due to your Deref implementation, this is a &'static str, so the method exists.

Related

Rust. Confusion around using functions from impl in global scope

I am doing examples from the Rust book but I dont understand this one.
How can a.tail() use tail(), when tail() is a function in the implementation of List and a is of Rc type?
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
impl List {
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
match self {
Cons(_, item) => Some(item),
Nil => None,
}
}
}
fn main() {
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
println!("a initial rc count = {}", Rc::strong_count(&a));
println!("a next item = {:?}", a.tail());
}
Thank you
Rc implements Deref. That means you can do &*rc and get back &T, like if it was a reference.
When you call a method, the compiler automatically inserts &s and *s as necessary. This is called autoref or autoderef. See What are Rust's exact auto-dereferencing rules? for more details.
That's due to automatic dereferencing, or Deref coercion. Rc is a Reference-counted smart pointer and it implements the Deref interface, which basically allows you to directly call methods on the value the Rc points to (in your case, the List enum).
See this and also this for more.

Can a function that takes a reference be passed as a closure argument that will provide owned values?

I am trying to simplify my closures, but I had a problem converting my closure to a reference to an associated function when the parameter is owned by the closure but the inner function call only expects a reference.
#![deny(clippy::pedantic)]
fn main() {
let borrowed_structs = vec![BorrowedStruct, BorrowedStruct];
//Selected into_iter specifically to reproduce the minimal scenario that closure gets value instead of reference
borrowed_structs
.into_iter()
.for_each(|consumed_struct: BorrowedStruct| MyStruct::my_method(&consumed_struct));
// I want to write it with static method reference like following line:
// for_each(MyStruct::my_method);
}
struct MyStruct;
struct BorrowedStruct;
impl MyStruct {
fn my_method(prm: &BorrowedStruct) {
prm.say_hello();
}
}
impl BorrowedStruct {
fn say_hello(&self) {
println!("hello");
}
}
Playground
Is it possible to simplify this code:
into_iter().for_each(|consumed_struct: BorrowedStruct| MyStruct::my_method(&consumed_struct));
To the following:
into_iter().for_each(MyStruct::my_method)
Note that into_iter here is only to reproduce to scenario that I own the value in my closure. I know that iter can be used in such scenario but it is not the real scenario that I am working on.
The answer to your general question is no. Types must match exactly when passing a function as a closure argument.
There are one-off workarounds, as shown in rodrigo's answer, but the general solution is to simply take the reference yourself, as you've done:
something_taking_a_closure(|owned_value| some_function_or_method(&owned_value))
I actually advocated for this case about two years ago as part of ergonomics revamp, but no one else seemed interested.
In your specific case, you can remove the type from the closure argument to make it more succinct:
.for_each(|consumed_struct| MyStruct::my_method(&consumed_struct))
I don't think there is a for_each_ref in trait Iterator yet. But you can write your own quite easily (playground):
trait MyIterator {
fn for_each_ref<F>(self, mut f: F)
where
Self: Iterator + Sized,
F: FnMut(&Self::Item),
{
self.for_each(|x| f(&x));
}
}
impl<I: Iterator> MyIterator for I {}
borrowed_structs
.into_iter()
.for_each_ref(MyStruct::my_method);
Another option, if you are able to change the prototype of the my_method function you can make it accept the value either by value or by reference with borrow:
impl MyStruct {
fn my_method(prm: impl Borrow<BorrowedStruct>) {
let prm = prm.borrow();
prm.say_hello();
}
}
And then your original code with .for_each(MyStruct::my_method) just works.
A third option is to use a generic wrapper function (playground):
fn bind_by_ref<T>(mut f: impl FnMut(&T)) -> impl FnMut(T) {
move |x| f(&x)
}
And then call the wrapped function with .for_each(bind_by_ref(MyStruct::my_method));.

How do I get a function pointer from a trait in Rust?

How do I get over something like this:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
I get this error:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
How do I pass a function pointer from a trait? Similar to what would happen in this case:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
What you're trying to do here is get a function pointer from a (to use Python terminology here, since Rust doesn't have a word for this) bound method. You can't.
Firstly, because Rust doesn't have a concept of "bound" methods; that is, you can't refer to a method with the invocant (the thing on the left of the .) already bound in place. If you want to construct a callable which approximates this, you'd use a closure; i.e. || self.a().
However, this still wouldn't work because closures aren't function pointers. There is no "base type" for callable things like in some other languages. Function pointers are a single, specific kind of callable; closures are completely different. Instead, there are traits which (when implemented) make a type callable. They are Fn, FnMut, and FnOnce. Because they are traits, you can't use them as types, and must instead use them from behind some layer of indirection, such as Box<FnOnce()> or &mut FnMut(i32) -> String.
Now, you could change Test to store an Option<Box<Fn()>> instead, but that still wouldn't help. That's because of the other, other problem: you're trying to store a reference to the struct inside of itself. This is not going to work well. If you manage to do this, you effectively render the Test value permanently unusable. More likely is that the compiler just won't let you get that far.
Aside: you can do it, but not without resorting to reference counting and dynamic borrow checking, which is out of scope here.
So the answer to your question as-asked is: you don't.
Let's change the question: instead of trying to crowbar a self-referential closure in, we can instead store a callable that doesn't attempt to capture the invocant at all.
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
The callable being stored is now a function that takes the invocant explicitly, side-stepping the issues with cyclic references. We can use this to store Test::a directly, by referring to it as a free function. Also note that because Test is the implementation type, I can also refer to it as Self.
Aside: I've also corrected your Test::new function. Rust doesn't have constructors, just functions that return values like any other.
If you're confident you will never want to store a closure in foo, you can replace Box<Fn(&Test)> with fn(&Test) instead. This limits you to function pointers, but avoids the extra allocation.
If you haven't already, I strongly urge you to read the Rust Book.
There are few mistakes with your code. new function (by the convention) should not take self reference, since it is expected to create Self type.
But the real issue is, Test::foo expecting a function type fn(), but Test::a's type is fn(&Test) == fn a(&self) if you change the type of foo to fn(&Test) it will work. Also you need to use function name with the trait name instead of self. Instead of assigning to self.a you should assign Test::a.
Here is the working version:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
Also if you gonna assign a field in new() function, and the value must always set, then there is no need to use Option instead it can be like that:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}

What is the correct type for a method on a lifetime-parameterized struct?

I have a struct that contains a reference and so it has a lifetime parameter. I'd like to pass around the function pointer of a method of this struct. Later, I will call that function with an instance of the struct. I ran into snags while trying to store the function pointer, eventually finding this solution:
struct Alpha<'a> { a: &'a u8 }
impl<'a> Alpha<'a> {
fn alpha(&self) -> u8 { *self.a }
}
struct Try1(fn(&Alpha) -> u8);
struct Try2(for<'z> fn(&Alpha<'z>) -> u8);
struct Try3<'z>(fn(&Alpha<'z>) -> u8);
fn main() {
Try1(Alpha::alpha); // Nope
Try2(Alpha::alpha); // Nope
Try3(Alpha::alpha);
}
Unfortunately, this solution doesn't work for my real case because I want to implement a trait that has its own notion of lifetimes:
trait Zippy {
fn greet<'a>(&self, &Alpha<'a>);
}
impl<'z> Zippy for Try3<'z> {
fn greet<'a>(&self, a: &Alpha<'a>) { println!("Hello, {}", self.0(a)) }
}
Produces the error:
error: mismatched types:
expected `&Alpha<'z>`,
found `&Alpha<'a>`
I feel that I shouldn't need to tie the lifetime of my struct Try3 to the lifetime of the parameter of the function pointer, but the compiler must be seeing something I'm not.
Unfortunately, the function alpha implemented on the struct Alpha effectively takes the struct's lifetime as a parameter, despite not actually using it. This is a limitation of the syntax for defining methods on structs with lifetimes. So even though it is possible to take a pointer to it as a for<'z> fn(&Alpha<'z>) -> u8, it is not possible to treat it as a fn(&Alpha) -> u8, even though the definition suggests this should be possible.
This can be worked around by defining a function that invokes the method and take a pointer to it instead:
fn workaround(a: &Alpha) -> u8 { Alpha::alpha(a) }
Try1(workaround);
In fact, it may be better to do it the other way around, with the definition in the function and the method invoking the function. Then when the function is invoked through a fn(&Alpha) -> u8 pointer a second jump won't be necessary into the method, and calls to the method can be inlined as calls to the function.

Rust invoke trait method on generic type parameter

Suppose I have a rust trait that contains a function that does not take a &self parameter. Is there a way for me to call this function based on a generic type parameter of the concrete type that implements that trait? For example, in the get_type_id function below, how do I successfully call the type_id() function for the CustomType trait?
pub trait TypeTrait {
fn type_id() -> u16;
}
pub struct CustomType {
// fields...
}
impl TypeTrait for CustomType {
fn type_id() -> u16 { 0 }
}
pub fn get_type_id<T : TypeTrait>() {
// how?
}
Thanks!
As Aatch mentioned, this isn't currently possible. A workaround is to use a dummy parameter to specify the type of Self:
pub trait TypeTrait {
fn type_id(_: Option<Self>) -> u16;
}
pub struct CustomType {
// fields...
}
impl TypeTrait for CustomType {
fn type_id(_: Option<CustomType>) -> u16 { 0 }
}
pub fn get_type_id<T : TypeTrait>() {
let type_id = TypeTrait::type_id(None::<T>);
}
Unfortunately, this isn't currently possible. It used to be, based on a implementation detail, however that was removed in favor of eventually implementing a proper way of doing this.
When it is eventually implemented, it may end up looking something like this: TypeTrait::<for T>::type_id(), however there is, currently, no syntax set in stone.
This is a known case and one that is fully intended to be supported, it is just unfortunate that it currently is not possible.
The full discussion about this topic (called associated methods) is here: https://github.com/mozilla/rust/issues/6894 and here: https://github.com/mozilla/rust/issues/8888

Resources