How to implement trait default implementation with parameter - rust

I want to implement getter and setter into the trait. For example:
trait StringValue {
value: String;
fn setValue(&self, value: String) {
self.value = value;
}
fn getValue(&self) -> String {
return self.value;
}
}
struct S;
impl StringValue for S {}
fn main() {
let s: S = S {};
s.setValue(String::from("test"));
println!("{}", s.getValue());
}
cargo build:
error: missing `fn`, `type`, or `const` for trait-item declaration
--> src/main.rs:1:20
|
1 | trait StringValue {
| ____________________^
2 | | value: String;
| |____^ missing `fn`, `type`, or `const`
error[E0609]: no field `value` on type `&Self`
--> src/main.rs:5:14
|
5 | self.value = value;
| ^^^^^
error[E0609]: no field `value` on type `&Self`
--> src/main.rs:9:21
|
9 | return self.value;
| ^^^^^
error: aborting due to 3 previous errors
Questions:
Can I use parameters into traits?
How can I fix the code?
If I want to use getter and setter into two different classes, how to implement it?

There is no way to do this in Rust (Currently). However, it's very likely that an alternative, similar, solution is enough for you. If you're interested in progress in that feature, you can check out https://github.com/rust-lang/rfcs/pull/1546 and https://github.com/nikomatsakis/fields-in-traits-rfc.
As for alternative solutions, simply leaving the implementation of the getter/setter to the struct is one option:
trait StringValue {
fn setValue(&mut self, value: String);
fn getValue(&self) -> &String;
}
struct S {
value: String,
}
impl StringValue for S {
fn setValue(&mut self, value: String) {
self.value = value;
}
fn getValue(&self) -> &String {
return &self.value;
}
}
fn main() {
let mut s: S = S {
value: String::from(""),
};
s.setValue(String::from("test"));
println!("{}", s.getValue());
}
But that might get slightly repetitive, specially if you have many such methods. You could try putting them in a separate state struct, add a getter for that state struct and use it to get the fields in the trait's default impl for all the getters/setters, and then just leave an impl of the getter for the state struct up to the containing one to define. However, it should be noted that if you expect these getter/setters to be flexible and be "overriden" (Not use the default), adding the intermediate State struct will make it so a struct overriding the default impl (For, say, get_value in the example with a constant string) needs/has an unused field in the State struct.Example:
trait StringValue {
fn get_state(&self) -> &State;
fn get_state_mut(&mut self) -> &mut State;
fn set_value(&mut self, value: String) {
self.get_state_mut().value = value
}
fn get_value(&self) -> &str {
self.get_state().value.as_str()
}
fn set_value2(&mut self, value: String) {
self.get_state_mut().value2 = value
}
fn get_value2(&self) -> &str {
self.get_state().value2.as_str()
}
}
struct State {
value: String,
value2: String,
}
struct OtherStruct {
state: State,
}
impl StringValue for OtherStruct {
fn get_state_mut(&mut self) -> &mut State {
&mut self.state
}
fn get_state(&self) -> &State {
&self.state
}
}
fn main() {
let mut s = OtherStruct {
state: State {
value: String::from(""),
value2: String::from(""),
},
};
s.set_value(String::from("test"));
dbg!(s.get_value());
s.set_value2(String::from("test2"));
dbg!(s.get_value2());
}
As mentioned by Ă–mer Erden, the https://crates.io/crates/getset crate might be useful.

From my experiment, getset crate doesn't work, because one has to implement the getter and setters in the impl Trait for Struct block, instead of the Struct block.
To get rid of the repetitive getter/setting implementation, you can use a macro. It is the easiest type of macro to write because you don't even need to process any tokens.
Say you have a struct and trait like below:
trait Test {
fn get_a(&self) -> i32;
fn get_b(&self) -> i32;
}
struct TT {
a: i32,
b: i32,
}
All you need to do is this:
macro_rules! getters {
{} => {
fn get_a(&self) -> i32 {
self.a
}
fn get_b(&self) -> i32 {
self.b
}
}
}
Then you can spam the getters!(); macro inside the impl block for any struct implementing Test trait.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d897baa26b8c32e5e7bde6c596714353

Related

What pattern to utilize to use a Vec of differing nested generic types/trait objects?

I'm trying to implement a pattern where different Processors can dictate the input type they take and produce a unified output (currently a fixed type, but I'd like to get it generic once this current implementation is working).
Below is a minimal example:
use std::convert::From;
use processor::NoOpProcessor;
use self::{
input::{Input, InputStore},
output::UnifiedOutput,
processor::{MultiplierProcessor, Processor, StringProcessor},
};
mod input {
use std::collections::HashMap;
#[derive(Debug)]
pub struct Input<T>(pub T);
#[derive(Default)]
pub struct InputStore(HashMap<String, String>);
impl InputStore {
pub fn insert<K, V>(mut self, key: K, value: V) -> Self
where
K: ToString,
V: ToString,
{
let key = key.to_string();
let value = value.to_string();
self.0.insert(key, value);
self
}
pub fn get<K, V>(&self, key: K) -> Option<Input<V>>
where
K: ToString,
for<'a> &'a String: Into<V>,
{
let key = key.to_string();
self.0.get(&key).map(|value| Input(value.into()))
}
}
}
mod processor {
use super::{input::Input, output::UnifiedOutput};
use super::I32Input;
pub struct NoOpProcessor;
pub trait Processor {
type I;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput;
}
impl Processor for NoOpProcessor {
type I = I32Input;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0 .0)
}
}
pub struct MultiplierProcessor(pub i32);
impl Processor for MultiplierProcessor {
type I = I32Input;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0 .0 * self.0)
}
}
pub struct StringProcessor;
impl Processor for StringProcessor {
type I = String;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0.parse().unwrap())
}
}
}
mod output {
#[derive(Debug)]
pub struct UnifiedOutput(pub i32);
}
pub fn main() {
let input_store = InputStore::default()
.insert("input_a", 123)
.insert("input_b", 567)
.insert("input_c", "789");
let processors = {
let mut labelled_processors = Vec::new();
// let mut labelled_processors: Vec<LabelledProcessor<Input<>>> = Vec::new(); // What's the correct type?
labelled_processors.push(LabelledProcessor("input_a", Box::new(NoOpProcessor)));
labelled_processors.push(LabelledProcessor(
"input_b",
Box::new(MultiplierProcessor(3)),
));
// labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor)));
labelled_processors
};
for processor in processors {
let output = retrieve_input_and_process(&input_store, processor);
println!("{:?}", output);
}
}
#[derive(Debug)]
pub struct I32Input(pub i32);
impl From<&String> for I32Input {
fn from(s: &String) -> Self {
Self(s.parse().unwrap())
}
}
struct LabelledProcessor<I>(&'static str, Box<dyn Processor<I = I>>)
where
for<'a> &'a String: Into<I>;
fn retrieve_input_and_process<T>(
store: &InputStore,
processor: LabelledProcessor<T>,
) -> UnifiedOutput
where
for<'a> &'a String: Into<T>,
{
let input = store.get(processor.0).unwrap();
processor.1.process(&input)
}
When // labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor))); is uncommented, I get the below compilation error:
error[E0271]: type mismatch resolving `<attempt2::processor::StringProcessor as attempt2::processor::Processor>::I == attempt2::I32Input`
--> src/attempt2.rs:101:63
|
101 | labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<attempt2::processor::StringProcessor as attempt2::processor::Processor>::I == attempt2::I32Input`
|
note: expected this to be `attempt2::I32Input`
--> src/attempt2.rs:75:18
|
75 | type I = String;
| ^^^^^^
= note: required for the cast from `attempt2::processor::StringProcessor` to the object type `dyn attempt2::processor::Processor<I = attempt2::I32Input>`
I think I've learnt enough to "get" what the issue is - the labelled_processors vec expects all its items to have the same type. My problem is I'm unsure how to rectify this. I've tried to leverage dynamic dispatch more (for example changing LabelledProcessor to struct LabelledProcessor(&'static str, Box<dyn Processor<dyn Input>>);). However these changes spiral to their own issues with the type system too.
Other answers I've found online generally don't address this level of complexity with respect to the nested generics/traits - stopping at 1 level with the answer being let vec_x: Vec<Box<dyn SomeTrait>> .... This makes me wonder if there's an obvious answer that can be reached that I've just missed or if there's a whole different pattern I should be employing instead to achieve this goal?
I'm aware of potentially utilizing enums as wel, but that would mean all usecases would need to be captured within this module and it may not be able to define inputs/outputs/processors in external modules.
A bit lost at this point.
--- EDIT ---
Some extra points:
This is just an example, so things like InputStore basically converting everything to String is just an implementation detail. It's mainly to symbolize the concept of "the type needs to comply with some trait to be accepted", I just chose String for simplicity.
One possible solution would be to make retrieve_input_and_process a method of LabelledProcessor, and then hide the type behind a trait:
use std::convert::From;
use processor::NoOpProcessor;
use self::{
input::InputStore,
output::UnifiedOutput,
processor::{MultiplierProcessor, Processor, StringProcessor},
};
mod input {
use std::collections::HashMap;
#[derive(Debug)]
pub struct Input<T>(pub T);
#[derive(Default)]
pub struct InputStore(HashMap<String, String>);
impl InputStore {
pub fn insert<K, V>(mut self, key: K, value: V) -> Self
where
K: ToString,
V: ToString,
{
let key = key.to_string();
let value = value.to_string();
self.0.insert(key, value);
self
}
pub fn get<K, V>(&self, key: K) -> Option<Input<V>>
where
K: ToString,
for<'a> &'a str: Into<V>,
{
let key = key.to_string();
self.0.get(&key).map(|value| Input(value.as_str().into()))
}
}
}
mod processor {
use super::{input::Input, output::UnifiedOutput};
use super::I32Input;
pub struct NoOpProcessor;
pub trait Processor {
type I;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput;
}
impl Processor for NoOpProcessor {
type I = I32Input;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0 .0)
}
}
pub struct MultiplierProcessor(pub i32);
impl Processor for MultiplierProcessor {
type I = I32Input;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0 .0 * self.0)
}
}
pub struct StringProcessor;
impl Processor for StringProcessor {
type I = String;
fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
UnifiedOutput(input.0.parse().unwrap())
}
}
}
mod output {
#[derive(Debug)]
pub struct UnifiedOutput(pub i32);
}
pub fn main() {
let input_store = InputStore::default()
.insert("input_a", 123)
.insert("input_b", 567)
.insert("input_c", "789");
let processors = {
let mut labelled_processors: Vec<Box<dyn LabelledProcessorRef>> = Vec::new();
labelled_processors.push(Box::new(LabelledProcessor(
"input_a",
Box::new(NoOpProcessor),
)));
labelled_processors.push(Box::new(LabelledProcessor(
"input_b",
Box::new(MultiplierProcessor(3)),
)));
labelled_processors.push(Box::new(LabelledProcessor(
"input_c",
Box::new(StringProcessor),
)));
labelled_processors
};
for processor in processors {
let output = processor.retrieve_input_and_process(&input_store);
println!("{:?}", output);
}
}
#[derive(Debug)]
pub struct I32Input(pub i32);
impl From<&str> for I32Input {
fn from(s: &str) -> Self {
Self(s.parse().unwrap())
}
}
struct LabelledProcessor<I>(&'static str, Box<dyn Processor<I = I>>);
impl<I> LabelledProcessorRef for LabelledProcessor<I>
where
for<'a> &'a str: Into<I>,
{
fn retrieve_input_and_process(&self, store: &InputStore) -> UnifiedOutput {
let input = store.get(self.0).unwrap();
self.1.process(&input)
}
}
trait LabelledProcessorRef {
fn retrieve_input_and_process(&self, store: &InputStore) -> UnifiedOutput;
}
UnifiedOutput(123)
UnifiedOutput(1701)
UnifiedOutput(789)

How do i resolve type annotations needed cannot infer type for type parameter `T` ? What type annotation is needed to compile this code?

The blockchain struct definition, It defines a type and i use the type
pub struct Blockchain<T = SledDb> {
pub storage: T,
pub chain: Vec<Block>,
pub tip: Arc<RwLock<String>>,
pub height: AtomicUsize,
pub mempool: Mempool,
pub wallet: Wallet,
pub accounts: Account,
pub stakes: Stake,
pub validators: Validator,
}
This code is checking if stake is valid.The code for mining a block, the error is immited by is_staking_valid function. I don't know what type its asking for since i already specified one.
impl<T: Storage> Blockchain<T> {
pub fn is_staking_valid(
balance: u64,
difficulty: u32,
timestamp: i64,
prev_hash: &String,
address: &String,
) -> bool {
let base = BigUint::new(vec![2]);
let balance_diff_mul = base.pow(256) * balance as u32;
let balance_diff = balance_diff_mul / difficulty as u64;
let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
let sha256_hash = digest(data_str);
let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
staking_hash <= balance_diff
}
pub fn mine_block(&mut self, data: &str) -> Option<Block> {
if self.mempool.transactions.len() < 2 {
info!("Skipping mining because no transaction in mempool");
return None;
}
let balance = self
.stakes
.get_balance(&self.wallet.get_public_key())
.clone();
let difficulty = self.get_difficulty();
info!("New block mining initialized with difficulty {}", difficulty);
let timestamp = Utc::now().timestamp();
let prev_hash = self.chain.last().unwrap().hash.clone();
let address = self.wallet.get_public_key();
if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
let block = self.create_block(&data, timestamp);
self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
Some(block)
} else {
None
}
}
}
Please find the compiler error below
error[E0282]: type annotations needed
--> src/blocks/chain.rs:173:12
|
173 | if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
For more information about this error, try `rustc --explain E0282`.
Minimized example:
pub struct Blockchain<T> {
pub storage: T,
}
impl<T> Blockchain<T> {
pub fn is_staking_valid() {
todo!()
}
pub fn mine_block(&mut self) {
Blockchain::is_staking_valid();
}
}
Playground
The reason for this error is that Blockchain::<T1>::is_staking_valid and Blockchain::<T2>::is_staking_valid are, as well as compiler is concerned, two separate, entirely unrelated functions. Yes, they have the same code, and yes, they will be deduplicated by the optimizer, but this doesn't have to be the case - e.g., if this function used some associated item available on T:
trait Stakable {
const IS_VALID: bool;
}
impl Stakable for () {
const IS_VALID: bool = false;
}
impl Stakable for i32 {
const IS_VALID: bool = true;
}
struct Blockchain<T> {
pub _storage: T,
}
impl<T: Stakable> Blockchain<T> {
fn validate() {
if !T::IS_VALID {
panic!("Type is not valid");
}
}
}
fn main() {
// This panics - we catch this panic and show that it has indeed happened
std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
// This executes successfully
Blockchain::<i32>::validate();
}
Playground
Because of the possible ambiguity, compiler refuses to choose by itself and forces you to make the selection explicitly.
So, you have several possible ways to go:
Make is_staking_valid a free function, instead of associated function of Blockchain. In this case, it won't be able to depend on Blockchain's type parameter, therefore the call will be unambiguous.
Call Self::is_staking_valid instead of Blockchain::is_staking_valid. In this case, Self will be replaced with Blockchain::<T>, with T taken from the currently executed method; this will, again, resolve ambiguity.
Make is_staking_valid a method on Blockchain, i.e. make it receive &self, and call it via self.is_staking_valid().
Not recommended, but still possible, - make is_staking_valid an associated function on Blockchain<T> for some specific T, e.g.:
pub struct Blockchain<T> {
pub storage: T,
}
impl Blockchain<()> {
// Note - no free type parameters here!
pub fn is_staking_valid() {
todo!()
}
}
impl<T> Blockchain<T> {
pub fn mine_block(&mut self) {
// Here, `Blockchain` is `Blockchain::<()>` - the method is set
Blockchain::is_staking_valid();
}
}

Storing types in a HashMap to dynamically instantiate them

I am trying to store structs in a HashMap keyed by string so that I can later create new objects by string. Think of a REST API where clients can get the server to instantiate a specific object by supplying a name.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", MyStruct);
h.insert("MyOtherStruct", MyOtherStruct);
// This is pseudo-code
let obj = h.get("MyStruct").unwrap()::new();
}
As I expected, this doesn't work due to syntax errors:
error: expected one of `.`, `;`, `?`, or an operator, found `::`
--> src/main.rs:25:41
|
25 | let obj = h.get("MyStruct").unwrap()::new();
| ^^ expected one of `.`, `;`, `?`, or an operator here
My second attempt was to store a reference to the new method of each struct instead of the types themselves.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", &MyStruct::new);
h.insert("MyOtherStruct", &MyOtherStruct::new);
let obj = h.get("MyStruct").unwrap()();
}
This fails because the fn items have different types and can't be stored in the same HashMap:
error[E0308]: mismatched types
--> src/main.rs:22:31
|
22 | h.insert("MyOtherStruct", &MyOtherStruct::new);
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected type `&fn() -> MyStruct {MyStruct::new}`
found type `&fn() -> MyOtherStruct {MyOtherStruct::new}`
Since I'm pretty new to Rust, I'm out of ideas. How can I solve this problem?
This is ultimately fundamentally impossible. In Rust, local variables are stored on the stack, which means that they have to have a fixed size, known at compile time. Your construction requires the size of the value on the stack to be determined at runtime.
The closest alternative is to move to trait objects, which introduce a layer of indirection:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {}
struct MyStruct;
impl NewThing for MyStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyStruct {}
struct MyOtherStruct;
impl NewThing for MyOtherStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyOtherStruct {}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStruct));
h.insert("MyOtherStruct", Box::new(MyOtherStruct));
let obj = h["MyStruct"].new();
}
You will find this pattern out in the world, such as in hyper's NewService.
what is [the value of &self of method new] when calling h["MyStruct"].new()
It's an instance of MyStruct or MyOtherStruct. The only reason that the same type can implement both traits is because there's no real unique state for the "factory" and the "instance". In more complicated implementations, these would be two different types.
Using the same type is common for such cases as sharing a reference-counted value.
See also:
Is it possible to have a constructor function in a trait?
Here is a more complex example of #Shepmaster's solution, using different types for Factories and the objects themselves:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {
fn execute(&mut self);
}
// MyStruct
struct MyStructFactory;
impl NewThing for MyStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyStruct {test: 12, name: "Test".into()})
}
}
struct MyStruct {
test: i32,
name: String
}
impl Thing for MyStruct {
fn execute(&mut self) {
self.test+=1;
println!("MyStruct {} {}", self.test, self.name);
}
}
// MyOtherStruct
struct MyOtherStructFactory;
impl NewThing for MyOtherStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyOtherStruct {my_member: 1})
}
}
struct MyOtherStruct {
my_member: u32
}
impl Thing for MyOtherStruct {
fn execute(&mut self) { println!("MyOtherStruct.my_member: {}", self.my_member); }
}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStructFactory));
h.insert("MyOtherStruct", Box::new(MyOtherStructFactory));
h["MyStruct"].new().execute();
h["MyOtherStruct"].new().execute();
}
You could use std::any::Any to erase the type of the entry. They use Any::downcast<T> to check if the entry at the location matches your type, and get a Ok(Box<T>)

Is it possible to use `impl Trait` as a function's return type in a trait definition?

Is it at all possible to define functions inside of traits as having impl Trait return types? I want to create a trait that can be implemented by multiple structs so that the new() functions of all of them returns an object that they can all be used in the same way without having to write code specific to each one.
trait A {
fn new() -> impl A;
}
However, I get the following error:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:2:17
|
2 | fn new() -> impl A;
| ^^^^^^
Is this a limitation of the current implementation of impl Trait or am I using it wrong?
As trentcl mentions, you cannot currently place impl Trait in the return position of a trait method.
From RFC 1522:
impl Trait may only be written within the return type of a freestanding or inherent-impl function, not in trait definitions or any non-return type position. They may also not appear in the return type of closure traits or function pointers, unless these are themselves part of a legal return type.
Eventually, we will want to allow the feature to be used within traits [...]
For now, you must use a boxed trait object:
trait A {
fn new() -> Box<dyn A>;
}
See also:
Is it possible to have a constructor function in a trait?
Why can a trait not construct itself?
How do I return an instance of a trait from a method?
Nightly only
If you wish to use unstable nightly features, you can use existential types (RFC 2071):
// 1.67.0-nightly (2022-11-13 e631891f7ad40eac3ef5)
#![feature(type_alias_impl_trait)]
#![feature(return_position_impl_trait_in_trait)]
trait FromTheFuture {
type Iter: Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter;
// Needs `return_position_impl_trait_in_trait`
fn returns_impl_trait(&self) -> impl Iterator<Item = u16>;
}
impl FromTheFuture for u8 {
// Needs `type_alias_impl_trait`
type Iter = impl Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter {
std::iter::repeat(*self).take(*self as usize)
}
fn returns_impl_trait(&self) -> impl Iterator<Item = u16> {
Some((*self).into()).into_iter()
}
}
fn main() {
for v in 7.returns_associated_type() {
println!("type_alias_impl_trait: {v}");
}
for v in 7.returns_impl_trait() {
println!("return_position_impl_trait_in_trait: {v}");
}
}
If you only need to return the specific type for which the trait is currently being implemented, you may be looking for Self.
trait A {
fn new() -> Self;
}
For example, this will compile:
trait A {
fn new() -> Self;
}
struct Person;
impl A for Person {
fn new() -> Person {
Person
}
}
Or, a fuller example, demonstrating using the trait:
trait A {
fn new<S: Into<String>>(name: S) -> Self;
fn get_name(&self) -> String;
}
struct Person {
name: String
}
impl A for Person {
fn new<S: Into<String>>(name: S) -> Person {
Person { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
struct Pet {
name: String
}
impl A for Pet {
fn new<S: Into<String>>(name: S) -> Pet {
Pet { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
fn main() {
let person = Person::new("Simon");
let pet = Pet::new("Buddy");
println!("{}'s pets name is {}", get_name(&person), get_name(&pet));
}
fn get_name<T: A>(a: &T) -> String {
a.get_name()
}
Playground
As a side note.. I have used String here in favor of &str references.. to reduce the need for explicit lifetimes and potentially a loss of focus on the question at hand. I believe it's generally the convention to return a &str reference when borrowing the content and that seems appropriate here.. however I didn't want to distract from the actual example too much.
You can get something similar even in the case where it's not returning Self by using an associated type and explicitly naming the return type:
trait B {}
struct C;
impl B for C {}
trait A {
type FReturn: B;
fn f() -> Self::FReturn;
}
struct Person;
impl A for Person {
type FReturn = C;
fn f() -> C {
C
}
}
Fairly new to Rust, so may need checking.
You could parametrise over the return type. This has limits, but they're less restrictive than simply returning Self.
trait A<T> where T: A<T> {
fn new() -> T;
}
// return a Self type
struct St1;
impl A<St1> for St1 {
fn new() -> St1 { St1 }
}
// return a different type
struct St2;
impl A<St1> for St2 {
fn new() -> St1 { St1 }
}
// won't compile as u32 doesn't implement A<u32>
struct St3;
impl A<u32> for St3 {
fn new() -> u32 { 0 }
}
The limit in this case is that you can only return a type T that implements A<T>. Here, St1 implements A<St1>, so it's OK for St2 to impl A<St2>. However, it wouldn't work with, for example,
impl A<St1> for St2 ...
impl A<St2> for St1 ...
For that you'd need to restrict the types further, with e.g.
trait A<T, U> where U: A<T, U>, T: A<U, T> {
fn new() -> T;
}
but I'm struggling to get my head round this last one.

How to call a trait method without a struct instance?

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.

Resources