I found a variable of type &Box<ListNode> can be assigned to a variable of type &ListNode. They are different types, I don't known the mechanism behind this. I thought it might because of the Deref coercion. But I think Deref corecion only occurs in methold solution or parameter passing. I am not sure. Could someone help me? Thanks you very much.
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
fn f1() {
let node = ListNode::new(0);
let mut ref_node:&ListNode = &node;
let mut ref_box :&Box<ListNode>= &Box::new(ListNode::new(10));
// why &Box<ListNode> can be assign to &ListNode?
ref_node = ref_box;
}
You are correct that this is because of Deref coercion. Coercions can be done at any coercion site which includes "let statements where an explicit type is given".
Related
This is a follow-up on the question asked here: Possible to implement dynamically-typed linked list in safe Rust?
I successfully implemented a dynamic type LinkedList using the std::any::Any trait.
However, I want to challenge myself by trying to implement it in another way, e.g. using generic type - Node where T can be any type, u32, u64, String, ...
Example
Node<String> -> Node<u32> -> Node<u64> -> Node<String> -> ...
My approach is to use a trait called Next to give Node<T> the ability to "go next".
Node<T> looks like this.
struct Node<T> {
data: T,
next: Option<Rc<RefCell<dyn Next>>>,
}
The trait Next looks like this.
pub trait Next {
fn borrow_next(&self) -> Option<Ref<dyn Next>>;
fn set_next(&mut self, next: Rc<RefCell<dyn Next>>);
}
These are the implementation of Next for any Node.
impl<T> Next for Node<T> {
fn set_next(&mut self, next: Rc<RefCell<dyn Next>>) {
self.next = Some(next);
}
fn borrow_next(&self) -> Option<Ref<dyn Next>> {
match &self.next {
None => None,
Some(stmt) => Some(stmt.borrow()),
}
}
}
Here are the implementations for the actual struct Node<T>.
impl<T> Node<T> {
pub fn new<P>(data: P) -> Node<P> {
Node::<P> { data, next: None }
}
pub fn new_wrapped<P>(data: P) -> Rc<RefCell<Node<P>>> {
Rc::new(RefCell::new(Node::<P>::new(data)))
}
pub fn into_wrapped(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
pub fn borrow_data(&self) -> &T {
&self.data
}
pub fn set_data(&mut self, data: T) {
self.data = data;
}
}
Lastly, the declaration and its implementations of methods of struct DynLinkedList, holding two fields, head and tail, look like this.
struct DynLinkedList {
head: Option<Rc<RefCell<dyn Next>>>,
tail: Option<Rc<RefCell<dyn Next>>>,
}
impl DynLinkedList {
pub fn new_empty() -> Self {
Self {
head: None,
tail: None,
}
}
pub fn new_with_node(node: Rc<RefCell<dyn Next>>) -> Self {
Self {
head: Some(node.clone()),
tail: Some(node),
}
}
pub fn append(&mut self, node: Rc<RefCell<dyn Next>>) {
self.tail.take().map_or_else(
|| self.head = Some(node.clone()),
|old_tail| old_tail.borrow_mut().set_next(node.clone()),
);
self.tail = Some(node);
}
}
Here comes the problem:
I am unable to access the data field of Node<T> as it is being treated as a trait object dyn Next by the compiler.
For example, this test would not work:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dynll_new_with_node() {
let node = Node::<u32>::new(77_u32);
let dynll = DynLinkedList::new_with_node(node.into_wrapped());
assert_eq!(&dynll.head.unwrap().borrow().borrow_data(), &77);
assert_eq!(&dynll.tail.unwrap().borrow().borrow_data(), &77)
}
}
The compiler error is:
error[E0599]: no method named `borrow_data` found for struct `Ref<'_, (dyn Next + 'static)>` in the current scope
--> src/dyn_ll_idea_five.rs:125:47
|
125 | assert_eq!(&*dynll.head.unwrap().borrow().borrow_data(), &77);
| ^^^^^^^^^^^ method not found in `Ref<'_, (dyn Next + 'static)>`
But, when the .borrow() after .unwrap() returns, it should return an object of type Node which would have the method .borrow_data(), how can I let Rust know that this is the case? Thank you.
I would effectively want to be able to do this:
let mut list = DynLinkedList::new();
list.push_front("hello".to_string());
list.push_back("world".to_string());
list.push_front(123);
list.push_back(456);
assert_eq!(list.pop_front(), Some("hello".to_string()));
assert_eq!(list.pop_back(), Some("world".to_string()));
assert_eq!(list.pop_front(), Some(123));
assert_eq!(list.pop_back(), Some(456));
Well, nowhere in the definition of trait Next does it talk about objects of type Node. Thus, how would the compiler ever know that you can call borrow_data on it? That's where you'd do the downcast via the Any trait.
What's more, the compiler would also want to know which sort of Node we're talking about. Node<i32> or Node<String> or what? And that's downright impossible because your list is dynamic and hence whatever type is contained within a node is also dynamic.
Let's take your example:
Node<String> -> Node<u32> -> Node<u64> -> Node<String> -> ...
So if that's your list, then, using very rough ugly pseudocode, what about this:
let x: String = my_list.head.borrow_data();
let y: u32 = my_list.head.next.borrow_data();
let z: u64 = my_list.head.next.next.borrow_data();
You see the problem here? How is the compiler to know, at compile time, that the third item in the list has type u64? This just isn't a case where generics work in the way you want it.
Given is a struct with a u32 field. It has exactly one overloaded method that can be used as both setter and getter for the field.
pub struct Struct {
value: u32
}
pub trait Trait<T> {
fn method(&mut self, arg: T);
}
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&mut self, arg: &mut u32) {
*arg = self.value;
}
}
A possible use of this structure could be as follows
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
s.method(&mut v);
println!("The value of s is: {}", v);
s.method(3);
s.method(&mut v);
println!("The value of s is: {}", v);
}
The advantage of calling an overloaded method instead of accessing the field directly serves two reasons when the struct is used in a ffi interface. On the one hand, the method can still make modifications to the value, such as first converting a &str to a CString and then storing the *const u8 as the value, which makes the string usable for C. On the other hand, overloading the method also makes it possible to use the names given for it in C instead of writing setValue and getValue, for example. However, as you can see here, one of the two methods does not need a mutable reference to self because it does not change the value field, but because the trait requires it, it is used in both cases anyway. The struct is not only configured and then used as argument in a ffi method, but can also occur as return value of such a method, in which case it will be returned as a immutable reference and should only be read from. The customized trait implementations would look like this
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&self, arg: &mut u32) {
*arg = self.value;
}
}
Obviously this won't work here because the second impl block doesn't have the same method signature as the trait. I already tried to define the self paramter as another generic parameter in the trait using the arbitrary_self_types features but unfortunately that didn't work.
You cannot parameterize over mutability.
See:
internals.rust-lang.org - Parameterisation over mutability.
internals.rust-lang.org - Generic mutability parameters.
How to implement a trait for any mutability?
How to avoid writing duplicate accessor functions for mutable and immutable references in Rust?
You can parameterize on self, but it will not be a method anymore, only an associated function:
pub trait Trait<This, T> {
fn method(this: This, arg: T);
}
impl Trait<&mut Self, u32> for Struct {
fn method(this: &mut Self, arg: u32) {
this.value = arg;
}
}
impl Trait<&Self, &mut u32> for Struct {
fn method(this: &Self, arg: &mut u32) {
*arg = this.value;
}
}
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
Struct::method(&s, &mut v);
println!("The value of s is: {}", v);
Struct::method(&mut s, 3);
Struct::method(&s, &mut v);
println!("The value of s is: {}", v);
}
Given the draft RFC Refined trait implementations that poses the possibility to refine a trait in its implementation, i.e. to write a less generic impl (e.g. safe method in the impl that is unsafe in the trait), it may be possible that you will be able to refine mutability in the future too (although I haven't seen discussions about that), but that will only relax the restriction when you work with a concrete instance, not with generics.
One way or the other, I don't think this design is correct. Just use normal value() and set_value() methods, it is simple and obvious.
I have the following in my tests which compiles and works well:
#[test]
fn zoo_test() {
let mut zoo = Zoo::new();
zoo.add(Monkey::new("m1".to_string()));
zoo.add(Limur::new("l1".to_string()));
assert_eq!(zoo.hi_all::<Monkey>(), vec![
"Monkey m1 says: ah ah ah".to_string(),
"Limur l1 says: yo".to_string()
]);
}
However, I'm a bit confused why zoo.hi_all::<Monkey>() works since it could be either monkey or limur. In other words I don't understand why it works for limur, or am I doing this wrong?
Edit: Here's the code I'm using for src/zoo.rs:
pub mod animal;
pub mod monkey;
pub mod limur;
use std::collections::VecDeque;
use animal::Animal;
pub struct Zoo<'a> {
list: VecDeque<Box<dyn Animal + 'a>>,
}
impl<'a> Zoo<'a> {
pub fn new() -> Zoo<'a> {
Zoo {
list: VecDeque::new(),
}
}
pub fn add<T>(&mut self, animal: T)
where
T: Animal + 'a,
{
self.list.push_back(Box::new(animal));
}
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
}
The type variable T is declared in the type of this function:
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
but is never actually used in the function's body! Removing that constraint will have no impact because there is no variable of type T mentioned in the function.
In fact, it never could be used in any practical way, because the elements of the VecDeque are of a specific concrete type, Box<dyn Animal> whereas, from the perspective of code inside the function, T could be any type that implements Animal.
If you need to filter the animals by type then I suggest you use an enum instead of trait objects, so you can discriminate on the enum variant.
I have a wrapper struct which stores an Option field. I would like to get a reference to the data stored in this field. The following code compiles.
struct Wrapper {
val: Option<i32>
}
impl Wrapper {
// lifetime specifier elided because Rust compiler can infer it
// to be fn my_deref<'a>(&'a self) -> Option<&'a i32>
fn my_deref(&self) -> Option<&i32> {
self.val.as_ref()
}
}
However, I prefer implementing Deref trait for Wrapper, so that I can have dereference coercion which is very nice. I tried the following code but the compiler complains.
use std::ops::Deref;
struct Wrapper {
val: Option<i32>
}
impl Deref for Wrapper {
type Target = Option<&i32>; // It tells me I need a lifetime specifier.
fn deref(&self) -> Option<&i32> {
self.val.as_ref()
}
}
I then tried to add a lifetime specifier, but failed again.
use std::ops::Deref;
struct Wrapper<'a> { // It tells me 'a is never used.
val: Option<i32>
}
impl<'a> Deref for Wrapper<'a> {
type Target = Option<&'a i32>;
fn deref(&'a self) -> Option<&'a i32> {
self.val.as_ref()
}
}
What is the correct way to implement deref that does the same thing as my_deref?
After reading turbulencetoo's comment, I come up with the following code, which does exactly what I intend. By program logic the Option field will never be None, so I can safely unwrap it. I must use Option to wrap it for some other reason irrelevant to this topic.
use std::ops::Deref;
struct Wrapper {
val: Option<i32>
}
impl Deref for Wrapper {
type Target = i32;
fn deref(&self) -> &i32 {
self.val.as_ref().unwrap()
}
}
Quoting turbulencetoo's comment below.
Implementing Deref for T does not mean that you can get a U from a T! It means that you can get an &U from an &T. In this case, the new Option that is created by the as_ref call in the deref function is not the same Option that your Wrapper stores, and as such you can't return a reference to it.
Consider this code:
pub trait Hello {
fn hello(&self);
}
impl Hello for Any {
fn hello(&self) {
println!("Hello!!!!!");
}
}
I remember seeing somewhere that there was a new feature in Rust that lets you implement a function that is directly accessible for all objects like this:
let foo = 0 as u8;
foo.hello();
Unfortunately, I have not been able to find it. Is there actually a global/universal "implementor"?
Well, you could make a generic implementation of your trait:
pub trait Hello {
fn hello(&self);
}
impl<T> Hello for T {
fn hello(&self) {
println!("Hello!!!!!");
}
}
fn main() {
let foo = 0 as u8;
foo.hello();
let bar = "world!".to_string();
bar.hello();
}
Note that Rust currently does not allow specialization of generics (although there is an open RFC on it) so your trait implementation has to work as-is for any T.