I am from C++ background and very new to rust. I have the following code which I have written to understand the code reusability, which is the sole purpose behind inheritance.
/* in animal.rs */
//declare Animal here
pub struct Animal;
// implement Animal here
impl Animal
{
pub fn breathe(&self)
{
println!("All animals breathe!");
}
}
// declare Dog here
pub struct Dog
{
pub parent: Animal
}
// implement Dog here
impl Dog
{
pub fn bark(&self)
{
println!("Dogs bark!");
}
pub fn breathe(&self)
{
self.parent.breathe();
}
}
/* in main.rs */
mod animal;
fn main()
{
let d = animal::Dog {parent : animal::Animal};
d.bark();
d.breathe();
}
If I don't implement the breathe function in Dog the compiler doesn't find it. In C++ the child inherits the functions from its parent. Can someone explain it?
Additional question: Can someone show some example code how dynamic/late binding works in rust. In C++ it is achieved by virtual functions.
There is no struct inheritance in Rust but you can use trait like in the following example to define a shared behavior. And you can see dyn AnimalTrait keyword which is used for dynamic dispatch in Rust.
trait AnimalTrait {
fn is_canine(&self) -> String {
return String::from("canine");
}
}
pub struct Dog;
impl AnimalTrait for Dog {}
pub struct Cat;
impl AnimalTrait for Cat {}
pub struct Mouse;
impl AnimalTrait for Mouse {
fn is_canine(&self) -> String {
return String::from("not canine");
}
}
fn main() {
let (d, c, m) = (Dog {}, Cat {}, Mouse {});
let all_animals: Vec<Box<dyn AnimalTrait>> = vec![Box::new(d), Box::new(c), Box::new(m)];
for e in all_animals {
match e.is_canine().as_str() {
"canine" => println!("I can tear apart well."),
"not canine" => println!("I will have hard time tearing apart."),
_ => (),
}
}
}
Related
I got two structs (Dog and Cat) which implements the same trait Animal.
#![allow(unused)]
pub struct Dog;
pub struct Cat;
trait Animal {
fn walk();
}
impl Animal for Dog {
fn walk() {
println!("Dog walking.");
}
}
impl Animal for Cat {
fn walk() {
println!("Cat walking.");
}
}
Then I have this function, which accepts a generic T type as a parameter. The generic type should implement the trait Animal and execute the method from the specified struct.
fn walk_module<T: Animal>(animal: T) {
T::walk();
}
I hope to use this like so.
fn main() {
walk_module(Cat); // prints Cat walking.
}
So everything is good, the animal is walking.
Playground here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7c16dfbf651b0b5871e771e7b64d17fb
However, the issue starts when I try to fetch the structs from an enum.
-- snips --
enum AnimalCategory {
Dog(Dog),
Cat(Cat)
}
fn get_the_animal(category: &str) -> AnimalCategory {
match category {
"dog" => AnimalCategory::Dog(Dog),
"cat" => AnimalCategory::Cat(Cat),
_ => AnimalCategory::Dog(Dog),
}
}
fn main() {
// Option 1
let animal = get_the_animal("dog");
walk_module(animal); // this errors now because enum AnimalCategory does not implement the Animal trait, and so the animal can't walk
}
I do not want to implement the Animal trait for AnimalCategory, but I know that I could implement methods for the enum AnimalCategory and have it return the correct variant and do exhaustive matching but it seems redundant, and I am not sure if I am doing it correctly.
-- snips --
impl AnimalCategory {
fn dog(self) -> Dog {
if let AnimalCategory::Dog(d) = self { d } else { panic!("Not dog!") }
}
fn cat(self) -> Cat {
if let AnimalCategory::Cat(c) = self { c } else { panic!("Not cat!") }
}
}
-- snips --
fn main() {
// OPTION 2
let animal = get_the_animal("dog");
if let AnimalCategory::Dog(Dog) = animal {
let dog = animal.dog();
walk_module(dog);
cry_module(dog); // this is where the redundancy comes
} else {
let cat = animal.cat();
walk_module(cat);
cry_module(cat); // this is where the redundancy comes
}
}
If I have to implement new methods, then I have to call the function/module twice. I would like to be able to do the OPTION 1 instead, but I could not figure it out.
I do not want to implement the Animal trait for Animal category
Why?
and I am not sure if I am doing it correctly.
I don't think that is the correct solution no.
As far as I'm concerned, implementing Animal for AnimalCategory sounds like a fine solution. An alternative would be to leverage dynamic dispatch but this requires a few changes:
Your trait currently is not object-safe, which means it can not be used for dynamic dispatch. The solution is simple enough: make it operate on instances:
trait Animal {
fn walk(&self);
}
impl Animal for Dog {
fn walk(&self) {
println!("Dog walking.");
}
}
impl Animal for Cat {
fn walk(&self) {
println!("Cat walking.");
}
}
this does require updating walk_module to work on the instance as well:
fn walk_module<T: Animal>(animal: T) {
animal.walk();
}
Next you need a cast method: if you have an AnimalCategory you should have a way to get an Animal out of it, without knowing which animal specifically:
impl AnimalCategory {
fn as_animal(&self) -> &dyn Animal {
match self {
Self::Dog(d) => d,
Self::Cat(c) => c,
}
}
}
now we can get our animal:
let animal = get_the_animal("dog");
walk_module(animal.as_animal());
however there is still an issue: &dyn Trait does not implement Trait by default, so we need to add one such implementation in order for our &dyn Animal to be an Animal. That's easy enough as we can just delegate to the underlying object (dyn Trait does implement Trait)
impl Animal for &dyn Animal {
fn walk(&self) { (*self).walk() }
}
et voilĂ .
Incidentally in the second example the retrieval methods are completely unnecessary, you can already get the instances from matching the enum:
fn main() {
let animal = get_the_animal("dog");
match animal {
AnimalCategory::Dog(dog) => {
walk_module(dog);
}
AnimalCategory::Cat(cat) => {
walk_module(cat);
}
}
}
I'd like to have a field in struct like this:
struct Foo<T> {
bar: Smart<T>
}
where bar could be either Rc<T or Weak<T>, depending on the "ownership relationships" between different instances of Foo. Is there any idiomatic way in Rust how to do this, other than to create a custom enum?
Is there any idiomatic way in Rust how to do this, other than to create a custom enum?
Just like most other "either this or that" choices in Rust, an enum is the idiomatic way.
An Peter's answer suggested, there is is no such abstraction in the stdlib. You can define a small enum to handle both cases:
use std::rc::{Rc, Weak};
enum MaybeStrong<T> {
Strong(Rc<T>),
Weak(Weak<T>),
}
impl<T> MaybeStrong<T> {
fn get(&self) -> Option<Rc<T>> {
match self {
MaybeStrong::Strong(t) => Some(Rc::clone(t)),
MaybeStrong::Weak(w) => w.upgrade(),
}
}
}
struct Foo<T> {
bar: MaybeStrong<T>
}
impl<T> Foo<T> {
fn from_weak(inner: Weak<T>) -> Self {
Self { bar: MaybeStrong::Weak(inner) }
}
fn from_strong(inner: Rc<T>) -> Self {
Self { bar: MaybeStrong::Strong(inner) }
}
fn say(&self) where T: std::fmt::Debug {
println!("{:?}", self.bar.get())
}
}
fn main() {
let inner = Rc::new("foo!");
Foo::from_weak(Rc::downgrade(&inner)).say();
Foo::from_strong(inner).say();
}
self.bar() will always return a Some if it was created from a strong pointer and return None in case it's a Weak and it's dangling. Notice that due to the fact that get() needs to create an owned Rc first, the method can't return a &T (including Option<&T>) because that &T could be dangling. This also means that all users of bar() will own one strong count on the inner value while processing, making it safe to use in any case.
This kind of construct is often called "Either" and there's a crate that looks like it can address some of the usual use-cases: https://docs.rs/either/1.5.3/either/
Then you could write
struct Foo<T> {
bar: Either<Weak<T>, Rc<T>>
}
Then an example function to get an Option<Rc<T>> might be:
impl <T> Foo<T> {
fn get_rc(self) -> Option<Rc<T>> {
self.bar
.map_left( |weak| weak.upgrade() )
.map_right( |v| Some(v) )
.into_inner()
}
}
Then it can be used like this:
fn main() {
let x = Rc::new(1);
let f_direct = Foo{ bar:Either::Right(x.clone()) };
println!("f_direct.get_rc() = {:?}", f_direct.get_rc());
let f_weak = Foo{ bar:Either::Left(Rc::downgrade(&x)) };
println!("f_weak.get_rc() = {:?}", f_weak.get_rc());
}
Link to complete example in the playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c20faaa46277550e16a3d3b24f3d1750
Using rust 1.2.0
Problem
I'm still in the process of learning Rust (coming from a Javascript background) and am trying to figure out if it is possible for one struct StructB to extend an existing struct StructA such that StructB has all the fields defined on StructA.
In Javascript (ES6 syntax) I could essentially do something like this...
class Person {
constructor (gender, age) {
this.gender = gender;
this.age = age;
}
}
class Child extends Person {
constructor (name, gender, age) {
super(gender, age);
this.name = name;
}
}
Constraints
StructA is from an external cargo package that I have no control over.
Current Progress
I found this blog post on single-inheritance which sounds like exactly what I need.
But trying to implement it resulted in this error message error: virtual structs have been removed from the language. Some searching later and I found out that it had been implemented and then removed per RFC-341 rather quickly.
Also found this thread about using traits, but since StructA is from an external cargo package I don't think it is possible for me to turn it into a trait.
So what would be the correct way to accomplish this in Rust?
There is nothing that exactly matches that. There are two concepts that come to mind.
Structural composition
struct Person {
age: u8,
}
struct Child {
person: Person,
has_toy: bool,
}
impl Person {
fn new(age: u8) -> Self {
Person { age: age }
}
fn age(&self) -> u8 {
self.age
}
}
impl Child {
fn new(age: u8, has_toy: bool) -> Self {
Child { person: Person::new(age), has_toy: has_toy }
}
fn age(&self) -> u8 {
self.person.age()
}
}
fn main() {
let p = Person::new(42);
let c = Child::new(7, true);
println!("I am {}", p.age());
println!("My child is {}", c.age());
}
You can simply embed one struct into another. The memory layout is nice and compact, but you have to manually delegate all the methods from Person to Child or lend out a &Person.
Traits
trait SayHi {
fn say_hi(&self);
}
struct Person {
age: u8,
}
struct Child {
age: u8,
has_toy: bool,
}
impl SayHi for Person {
fn say_hi(&self) {
println!("Greetings. I am {}", self.age)
}
}
impl SayHi for Child {
fn say_hi(&self) {
if self.has_toy {
println!("I'm only {}, but I have a toy!", self.age)
} else {
println!("I'm only {}, and I don't even have a toy!", self.age)
}
}
}
fn greet<T>(thing: T)
where T: SayHi
{
thing.say_hi()
}
fn main() {
let p = Person { age: 42 };
let c = Child { age: 7, has_toy: true };
greet(p);
greet(c);
}
You can combine these two concepts, of course.
As DK. mentions, you could choose to implement Deref or DerefMut. However, I do not agree that these traits should be used in this manner. My argument is akin to the argument that using classical object-oriented inheritance simply for code reuse is the wrong thing. "Favor composition over inheritance" => "favor composition over Deref". However, I do hold out hope for a language feature that enables succinct delegation, reducing the annoyance of composition.
Rust does not have struct inheritance of any kind. If you want StructB to contain the same fields as StructA, then you need to use composition.
struct StructB {
a: StructA,
// other fields...
}
Also, to clarify, traits are only able to define methods and associated types; they cannot define fields.
If you want to be able to use a StructB as a StructA, you can get some of the way there by implementing the Deref and DerefMut traits, which will allow the compiler to implicitly cast pointers to StructBs to pointers to StructAs:
struct StructA;
impl StructA {
fn name(&self) -> &'static str {
"Anna"
}
}
struct StructB {
a: StructA,
// other fields...
}
impl std::ops::Deref for StructB {
type Target = StructA;
fn deref(&self) -> &Self::Target {
&self.a
}
}
fn main() {
let b = StructB { a: StructA };
println!("{}", b.name());
}
Another alternative is to use generics:
trait IAnimalData {}
struct Animal<D: IAnimalData> {
name: String,
age: i64,
child_data: D,
}
struct Dog {
favorite_toy: String,
}
impl IAnimalData for Dog {}
And then you can implement "child" methods like this, which will only apply to dogs:
impl Animal<Dog> {
pub fn bark(&self) -> String {
return "bark!".to_owned();
}
}
And if you want parent methods that apply to all animals, you can implement them like this:
// implements the 'breathe' method for all animals
impl<T: IAnimalData> Animal<T> {
fn breathe() {}
}
The good part is that you don't have to go through the pain of forwarding methods in Dog to methods in Animal; you can use them directly inside impl Animal<Dog>. Also, you can access any fields defined in Animal from any method of Animal<Dog>. The bad part is that your inheritance chain is always visible (that is, you will probably never use Dog in your code, but rather Animal<Dog>). Also, if the inheritance chain is long, you might get some very silly, long-winded types, like Animal<Dog<Chihuahua>>. I guess at that point a type alias would be advisable.
One thing that is good to mention for new corners in Rust is the way to design your structs/classes/traits. Try to keep your traits small and simple.
And take advantage of possible to use multiples traits for the same class:
trait Animal {
fn print_name(&self);
}
trait Attack {
fn can_kick(&self) -> bool {
false
}
}
trait Behavior {
fn can_fly(&self) -> bool {
true
}
}
impl Aminal for Bird {}
impl Behavior for Bird {}
impl Attack for Bird {}
Ok, the answer is very simple. Use macro.
macro_rules! Person {
(#[derive($($derive:meta),*)] $pub:vis struct $name:ident { $($fpub:vis $field:ident : $type:ty,)* }) => {
#[derive($($derive),*)]
$pub struct $name {
// required for all persones
age: i64,
$($fpub $field : $type,)*
}
impl $name {
$pub fn new(age:i64,$($field:$type,)*) -> Self{
Self{
age,
$($field,)*
}
}
}
}
}
And then use it like this:
Person! {
pub stuct Kid {
extra_field: String,
}
}
I have a builder pattern implemented for my struct:
pub struct Struct {
pub grand_finals_modifier: bool,
}
impl Struct {
pub fn new() -> Struct {
Struct {
grand_finals_modifier: false,
}
}
pub fn grand_finals_modifier<'a>(&'a mut self, name: bool) -> &'a mut Struct {
self.grand_finals_modifier = grand_finals_modifier;
self
}
}
Is it possible in Rust to make a macro for methods like this to generalize and avoid a lot of duplicating code? Something that we can use as the following:
impl Struct {
builder_field!(hello, bool);
}
After reading the documentation, I've come up with this code:
macro_rules! builder_field {
($field:ident, $field_type:ty) => {
pub fn $field<'a>(&'a mut self,
$field: $field_type) -> &'a mut Self {
self.$field = $field;
self
}
};
}
struct Struct {
pub hello: bool,
}
impl Struct {
builder_field!(hello, bool);
}
fn main() {
let mut s = Struct {
hello: false,
};
s.hello(true);
println!("Struct hello is: {}", s.hello);
}
It does exactly what I need: creates a public builder method with specified name, specified member and type.
To complement the already accepted answer, since it is 4 years old by now, you should check out the crate rust-derive-builder. It uses procedural macros to automatically implement the builder pattern for any struct.
If I have a struct with a method that doesn't have self as an argument, I can call the method via SomeStruct::method(). I can't seem to do the same with a method that's defined from a trait. For example:
trait SomeTrait {
fn one_trait() -> uint;
}
struct SomeStruct;
impl SomeStruct {
fn one_notrait() -> uint {
1u
}
}
impl SomeTrait for SomeStruct {
fn one_trait() -> uint {
1u
}
}
#[test]
fn testing() {
SomeStruct::one_trait(); // doesn't compile
SomeStruct::one_notrait(); // compiles
}
The compiler gives the error "unresolved name 'SomeStruct::one_trait.'"
How can I call a struct's implementation of a trait method directly?
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
fn main() {
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}
From Advanced Trait
I believe this is currently not possible. The problem is that you cannot explicitly specify the Self type. But there is an active RFC in the pipeline which should allow this when implemented.
In the meantime, you could work around it like this:
trait SomeTrait {
fn one_trait(&self) -> uint;
}
struct Static<T>;
struct SomeStruct;
impl SomeTrait for Static<SomeStruct> {
fn one_trait(&self) -> uint { 1 }
}
fn main() {
let type_to_uint = Static::<SomeStruct>.one_trait();
println!("{}", type_to_uint);
}
This is how I map a type to an integer (if that's what you're after). It's done without having a value of type T. The dummy value, Static<T>, has a size of zero.