How to call default trait method? [duplicate] - rust

Some trait methods have default implementations which can be overwritten by an implementer. How can I use the default implementation for a struct that overwrites the default?
For example:
trait SomeTrait {
fn get_num(&self) -> i32;
fn add_to_num(&self) -> i32 {
self.get_num() + 1
}
}
struct SomeStruct;
impl SomeTrait for SomeStruct {
fn get_num(&self) -> i32 {
3
}
fn add_to_num(&self) -> i32 {
self.get_num() + 2
}
}
fn main() {
let the_struct = SomeStruct;
println!("{}", the_struct.add_to_num()); // how can I get this to print 4 instead of 5?
}

One solution I've come up with is to define a dummy struct that contains the struct I want to change. I can then cherry-pick which methods I want to overwrite and which ones I want to keep as the default.
To extend the original example:
trait SomeTrait {
fn get_num(&self) -> i32;
fn add_to_num(&self) -> i32 {
self.get_num() + 1
}
}
struct SomeStruct;
impl SomeTrait for SomeStruct {
fn get_num(&self) -> i32 {
3
}
fn add_to_num(&self) -> i32 {
self.get_num() + 2
}
}
fn main() {
struct SomeOtherStruct {
base: SomeStruct,
}
impl SomeTrait for SomeOtherStruct {
fn get_num(&self) -> i32 {
self.base.get_num()
}
//This dummy struct keeps the default behavior of add_to_num()
}
let the_struct = SomeStruct;
println!("{}", the_struct.add_to_num());
//now we can call the default method using the original struct's data.
println!("{}", SomeOtherStruct { base: the_struct }.add_to_num());
}

Related

Rust - Casting super trait to trait

I have a container where I can store items implementing the CommonBase trait and I have some other traits (TypeA and TypeB for example, but there can be unknown number of other TypeX traits) with the CommonBase as their super trait. I store objects implementing ItemA to container and I can get a reference to item back from the container, but as reference to the CommonBase.
I want to cast the item back to its original type like this:
fn cast_to<T: SuperTrait>(val: dyn CommonBase) -> Result<T, dyn Error> {...}
Can anyone help please?
Here is my experimental code
use std::error::Error;
use std::rc::Rc;
pub trait CommonBase {
fn to_common(self: &Self);
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) { todo!() }
}
impl TypeA for StructA {
fn do_a(self: &Self) { todo!() }
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) { todo!() }
}
impl TypeB for StructB {
fn do_b(self: &Self) { todo!() }
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(self: &mut Self, item: Rc<dyn CommonBase>) {
self.items.push(item);
}
pub fn get(self, idx: usize) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(val: Rc<dyn CommonBase>) -> Result<Rc<dyn T>, Box<dyn Error>> {...} // <- some magic is done here
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get_common(0); // actually TypeA
let stored_a: Rc<dyn TypeA> = cast_to(stored_a_as_common).unwrap();
stored_a.do_a();
}
Here is your code with a few additions.
For this, you need std::any::Any.
Each struct subject to dynamic cast should be known as dyn Any in order to try the dynamic cast; this is the purpose of .as_any() and .as_any_mut() in the example.
Using .downcast_ref() or .downcast_mut() requires you target a type, not a trait.
I don't think you can have at the same time two Rcs pointing towards the same struct but declared with different dyn traits.
The best to do, in my opinion, is to only deal with references (wherever they come from, Rc or something else).
You expected an Error when the dynamic cast is impossible, then I wrote the function this way.
Note however that .downcast_ref() returns an Option and this is generally good enough (None means that the cast is impossible); we could simplify the code with just this line val.as_any().downcast_ref::<T>().
use std::error::Error;
use std::rc::Rc;
use std::any::Any;
pub trait CommonBase: Any {
fn to_common(self: &Self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeA for StructA {
fn do_a(self: &Self) {
println!("doing a");
}
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeB for StructB {
fn do_b(self: &Self) {
println!("doing b");
}
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(
self: &mut Self,
item: Rc<dyn CommonBase>,
) {
self.items.push(item);
}
pub fn get(
&self,
idx: usize,
) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(
val: &dyn CommonBase
) -> Result<&T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any().downcast_ref::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
#[allow(dead_code)] // unused in this example
fn cast_to_mut<T: CommonBase>(
val: &mut dyn CommonBase
) -> Result<&mut T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any_mut().downcast_mut::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get(0); // actually TypeA
let stored_a: &dyn TypeA =
cast_to::<StructA>(stored_a_as_common.as_ref()).unwrap();
stored_a.do_a();
let stored_b_as_common: Rc<dyn CommonBase> = container.get(1); // actually TypeB
let stored_b: &dyn TypeB =
cast_to::<StructB>(stored_b_as_common.as_ref()).unwrap();
stored_b.do_b();
}
/*
doing a
doing b
*/

How to define a Vec in Rust to support containing multiple types of structs that implement a same trait?

In c++, I can define a parent class, and the type in vector can just be the father class type. So how to implement that in Rust?
Like for this example:
I defined two types of Integer who both implement the trait Object, now I want to put them in a same vector, is there any way to achieve that?
pub trait Object<T: Object<T>+Clone> {
fn sub(&self, x: &T) -> T {
x.clone() //this is a useless implementation, just for structs don't need to implement this method.
}
}
#[derive(Debug, Copy, Clone)]
pub struct Integer {
val: i32
}
impl Integer {
pub fn get(&self) -> i32 {
self.val
}
pub fn new(val: i32) -> Self {
Integer {
val
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct Int {
val: i32
}
impl Int {
pub fn get(&self) -> i32 {
self.val
}
pub fn new(val: i32) -> Self {
Int {
val
}
}
}
impl Object<Int> for Int {
fn sub(&self, rhs: &Int) -> Int {
Int {
val: self.val - rhs.get()
}
}
}
impl Object<Integer> for Integer {
fn sub(&self, rhs: &Integer) -> Integer {
Integer {
val: self.val - rhs.get()
}
}
}
fn main() {
let mut v: Vec<Box<dyn Object>> = Vec::new();
v.push(Box::new(Integer::new(1)));
v.push(Box::new(Int::new(2)));
}
Thanks a lot.
There are several aspects of your design that don't fit in Rust:
trait Object<T: Object<T>+Clone> doesn't help - Rust doesn't do CRTP, just use Self instead.
for Object to be object-safe (necessary to put it in a vector), it can't be parameterized by type. A type parameter means you get a completely separate trait for each type.
Object::sub() can't return the result by value, because the size of the value can differ for different implementations, so it wouldn't be object-safe. It must return Box<dyn Object> instead.
The code modified as indicated looks like this:
pub trait Object {
fn get(&self) -> i32;
fn sub(&self, x: &dyn Object) -> Box<dyn Object>;
}
#[derive(Debug, Copy, Clone)]
pub struct Integer {
val: i32,
}
impl Integer {
fn new(val: i32) -> Box<dyn Object> {
Box::new(Int { val })
}
}
impl Object for Integer {
fn get(&self) -> i32 {
self.val
}
fn sub(&self, rhs: &dyn Object) -> Box<dyn Object> {
Integer::new(self.val - rhs.get())
}
}
#[derive(Debug, Copy, Clone)]
pub struct Int {
val: i32,
}
impl Int {
fn new(val: i32) -> Box<dyn Object> {
Box::new(Int { val })
}
}
impl Object for Int {
fn get(&self) -> i32 {
self.val
}
fn sub(&self, rhs: &dyn Object) -> Box<dyn Object> {
Int::new(self.val - rhs.get())
}
}
fn main() {
let mut v: Vec<Box<dyn Object>> = vec![];
v.push(Integer::new(1));
v.push(Int::new(2));
v.push(v[0].sub(v[1].as_ref()));
for o in &v {
println!("{}", o.get());
}
}
Playground
I think you can combine trait and provide a blank implementation, then use that in vector
trait TraitA {}
trait TraitB {}
trait CombinedTraitATraitB: TraitA + TraitB {}
impl<T> CombinedTraitATraitB for T where T: TraitA + TraitB {}
let vector: Vec<Box<dyn CombinedTraitATraitB>> = vec![];

Converting an Option<impl Trait> to an Option<Box<dyn Trait>>

Is it possible to map an Option<impl Trait> to a Option<Box<dyn Trait>>? If the argument to new() is not an Option, it is possible to assign it to a struct with Some(Box::new(item)). Why does this work and the map doesn't?
trait TestTrait {}
impl TestTrait for i32 {}
struct TestStruct {
item: Option<Box<dyn TestTrait>>
}
impl TestStruct {
pub fn new(item: Option<impl TestTrait + 'static>) -> Self {
let item: Option<Box<dyn TestTrait>> = item.map(|i| Box::new(i));
Self {
item
}
}
}
fn main() {
let num:i32 = 0;
let s = TestStruct::new(Some(num));
}
It looks like the compiler can not inference the correct type for the closure. If you specify it explicitly then everything works (playground):
trait TestTrait {}
impl TestTrait for i32 {}
struct TestStruct {
item: Option<Box<dyn TestTrait>>
}
impl TestStruct {
pub fn new(item: Option<impl TestTrait + 'static>) -> Self {
let item = item.map(
|i| -> Box<dyn TestTrait> {
Box::new(i)
}
);
Self {
item
}
}
}
fn main() {
let num:i32 = 0;
let _ = TestStruct::new(Some(num));
}

Cannot call a fn<T: X> from an impl<T: X> because X is not satisfied for T

I have a trait RawFd that is implemented for each type that satisfies special requirements.
Now I have a function that accepts any type that implements RawFd. And I have a trait with an implementation for each T that implements RawFd.
However I cannot call my function from my trait even if T implements RawFd:
pub trait RawFd {
fn raw_fd(&self) -> u64;
}
#[cfg(unix)]
impl<T: std::os::unix::io::AsRawFd> RawFd for T {
fn raw_fd(&self) -> u64 { self.as_raw_fd() as u64 }
}
#[cfg(windows)]
impl<T: std::os::windows::io::AsRawSocket> RawFd for T {
fn raw_fd(&self) -> u64 { self.as_raw_socket() as u64 }
}
fn print_fd<T: RawFd>(p: T) {
println!("{}", p.raw_fd());
}
trait Printable {
fn print(&self);
}
impl<T: RawFd> Printable for T {
fn print(&self) {
print_fd(self);
}
}
What is my mistake here and how can I solve it.
(Link to playground)
If you expect to use print_fd() with a reference you must do this:
fn print_fd(p: &impl RawFd) {
println!("{}", p.raw_fd());
}
or
fn print_fd<T: RawFd>(p: &T) {
println!("{}", p.raw_fd());
}
Or you must take self by value:
impl<T: RawFd> Printable for T {
fn print(self) {
print_fd(self);
}
}
Or you could use clone:
impl<T> Printable for T where T: Clone + RawFd {
fn print(&self) {
print_fd(self.clone());
}
}

How can I use the default implementation of a trait method instead of the type's custom implementation?

Some trait methods have default implementations which can be overwritten by an implementer. How can I use the default implementation for a struct that overwrites the default?
For example:
trait SomeTrait {
fn get_num(&self) -> i32;
fn add_to_num(&self) -> i32 {
self.get_num() + 1
}
}
struct SomeStruct;
impl SomeTrait for SomeStruct {
fn get_num(&self) -> i32 {
3
}
fn add_to_num(&self) -> i32 {
self.get_num() + 2
}
}
fn main() {
let the_struct = SomeStruct;
println!("{}", the_struct.add_to_num()); // how can I get this to print 4 instead of 5?
}
One solution I've come up with is to define a dummy struct that contains the struct I want to change. I can then cherry-pick which methods I want to overwrite and which ones I want to keep as the default.
To extend the original example:
trait SomeTrait {
fn get_num(&self) -> i32;
fn add_to_num(&self) -> i32 {
self.get_num() + 1
}
}
struct SomeStruct;
impl SomeTrait for SomeStruct {
fn get_num(&self) -> i32 {
3
}
fn add_to_num(&self) -> i32 {
self.get_num() + 2
}
}
fn main() {
struct SomeOtherStruct {
base: SomeStruct,
}
impl SomeTrait for SomeOtherStruct {
fn get_num(&self) -> i32 {
self.base.get_num()
}
//This dummy struct keeps the default behavior of add_to_num()
}
let the_struct = SomeStruct;
println!("{}", the_struct.add_to_num());
//now we can call the default method using the original struct's data.
println!("{}", SomeOtherStruct { base: the_struct }.add_to_num());
}

Resources