I have the following trait:
trait MyTrait {
type A;
type B;
fn foo(a: Self::A) -> Self::B;
fn bar(&self);
}
There are other functions like bar that must be always implemented by the user of the trait.
I would like to give foo a default implementation, but only when the type A = B.
Pseudo-Rust code:
impl??? MyTrait where Self::A = Self::B ??? {
fn foo(a: Self::A) -> Self::B {
a
}
}
This would be possible:
struct S1 {}
impl MyTrait for S1 {
type A = u32;
type B = f32;
// `A` is different from `B`, so I have to implement `foo`
fn foo(a: u32) -> f32 {
a as f32
}
fn bar(&self) {
println!("S1::bar");
}
}
struct S2 {}
impl MyTrait for S2 {
type A = u32;
type B = u32;
// `A` is the same as `B`, so I don't have to implement `foo`,
// it uses the default impl
fn bar(&self) {
println!("S2::bar");
}
}
Is that possible in Rust?
You can provide a default implementation in the trait definition itself by introducing a redundant type parameter:
trait MyTrait {
type A;
type B;
fn foo<T>(a: Self::A) -> Self::B
where
Self: MyTrait<A = T, B = T>,
{
a
}
}
This default implementation can be overridden for individual types. However, the specialized versions will inherit the trait bound from the definition of foo() on the trait so you can only actually call the method if A == B:
struct S1;
impl MyTrait for S1 {
type A = u32;
type B = f32;
fn foo<T>(a: Self::A) -> Self::B {
a as f32
}
}
struct S2;
impl MyTrait for S2 {
type A = u32;
type B = u32;
}
fn main() {
S1::foo(42); // Fails with compiler error
S2::foo(42); // Works fine
}
Rust also has an unstable impl specialization feature, but I don't think it can be used to achieve what you want.
Will this suffice?:
trait MyTrait {
type A;
type B;
fn foo(a: Self::A) -> Self::B;
}
trait MyTraitId {
type AB;
}
impl<P> MyTrait for P
where
P: MyTraitId
{
type A = P::AB;
type B = P::AB;
fn foo(a: Self::A) -> Self::B {
a
}
}
struct S2;
impl MyTraitId for S2 {
type AB = i32;
}
Rust Playground
As noted, it'll bump into problems if MyTrait as other methods that MyTraitId can't provide an implementation for.
Extending user31601's answer and using the remark from Sven Marnach's comment, here's an implementation of the trait with additional functions using the "delegate methods" pattern:
trait MyTrait {
type A;
type B;
fn foo(a: Self::A) -> Self::B;
fn bar();
}
trait MyTraitId {
type AB;
fn bar_delegate();
}
impl<P> MyTrait for P
where
P: MyTraitId,
{
type A = P::AB;
type B = P::AB;
fn foo(a: Self::A) -> Self::B {
a
}
fn bar() {
<Self as MyTraitId>::bar_delegate();
}
}
struct S2;
impl MyTraitId for S2 {
type AB = i32;
fn bar_delegate() {
println!("bar called");
}
}
fn main() {
<S2 as MyTrait>::bar(); // prints "bar called"
}
Playground
Related
I have two structs say struct A and struct B. I have the Add implemented for A and B.
impl Add<&B> for A{
type Output = A;
fn add(self, rhs: &B) -> A{
--snip--
}
Now, I want to implement the AddAssign, but I think there should be an idiomatic way to use Add. Something like:
impl AddAssign<&B> for A {
fn add_assign(&mut self, rhs: &B) {
*self = *self + rhs;
}
}
Is there a way to do it?
It's a good idea to chain them together, but you're running to the issue of a dereference causing a move out of a borrowed value. It's typically easier to go the other way around, and implement AddAssign, then use that in Add. You can change the self to be mut self, which takes ownership as usual, but just allows it to be modified in place, then immediately returned:
struct A;
struct B;
impl Add<&B> for A {
type Output = A;
fn add(mut self, rhs: &B) -> A {
self += rhs;
self
}
}
impl AddAssign<&B> for A {
fn add_assign(&mut self, rhs: &B) {
todo!()
}
}
If you really need them to be in that order, A has to be Copy and/or Clone. That could look like:
#[derive(Clone, Copy)]
struct A;
struct B;
impl Add<&B> for A {
type Output = A;
fn add(mut self, rhs: &B) -> A {
todo!()
}
}
impl AddAssign<&B> for A {
fn add_assign(&mut self, rhs: &B) {
*self = *self + rhs
}
}
or
#[derive(Clone)]
struct A;
struct B;
impl Add<&B> for A {
type Output = A;
fn add(mut self, rhs: &B) -> A {
todo!()
}
}
impl AddAssign<&B> for A {
fn add_assign(&mut self, rhs: &B) {
*self = self.clone() + rhs
}
}
I want to have a trait that can be implemented for T and &T but has methods that always return T.
What I would like to do is something like this
use std::borrow::ToOwned;
trait Foo<X: ToOwned> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Owned;
}
struct Float(f64);
impl Foo<f64> for Float {
fn f(&self, x: f64) -> f64 {
x + self.0
}
fn g(&self) -> f64 {
self.0 * 2.0
}
}
struct List(Vec<f64>);
impl Foo<&Vec<f64>> for List {
fn f(&self, x: &Vec<f64>) -> f64 {
x.iter().sum()
}
// Error here - `&Vec<f64>` return type expected
fn g(&self) -> Vec<f64> {
self.0.iter().map(|&x| 2.0 * x).collect()
}
}
fn main() {
let float = Float(2.0);
println!("{} {}", float.f(3.0), float.g());
let list = List(vec![0.0, 1.0, 2.0]);
println!("{} {:?}", list.f(&vec![1.0, 2.0]), list.g());
}
I know that one option is to have a trait that defines the output type like so
trait FooReturn {
type Output;
}
trait Foo<X: FooReturn> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Output;
}
then implement the trait for all relevant types, but I was wondering if there was a more standard/robust way to do this.
This is how you would do it once specialization is complete. Meanwhile, I couldn't even get a simple working example to compile on 1.55.0-nightly.
#![feature(specialization)]
trait MaybeOwned {
type Owned;
}
default impl<X> MaybeOwned for X {
type Owned = X;
}
impl<'a, X> MaybeOwned for &'a X {
type Owned = X;
}
trait Foo<X: MaybeOwned> {
fn f(&self, x: &X) -> f64;
fn g(&self) -> <X as MaybeOwned>::Owned;
}
This is valid code:
use std::rc::Rc;
use std::sync::{Arc, Mutex};
fn foo(n: i32) {
println!("n = {}", n)
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(*b);
foo(*(c.lock().unwrap()));
foo(*((*d).lock().unwrap()));
}
Are there any traits (or anything else) that I can implement so that the function calls could simply become:
foo(a);
foo(b);
foo(c);
foo(d);
What is the Rust idiomatic way for handling the actual data and not caring about how the data is protected/wrapped?
As others have pointed out, it is a bad idea to ignore the fallibility of Mutex::lock. However for the other cases, you can make your function accept owned values and references transparently by using Borrow:
use std::borrow::Borrow;
use std::rc::Rc;
fn foo (n: impl Borrow<i32>) {
println!("n = {}", n.borrow())
}
fn main() {
let a = 1;
let b = Rc::new (2);
let c = &3;
foo (a);
foo (b);
foo (c);
}
Playground
Here is an extremely literal answer to your specific question. I wouldn't use it.
use std::{
rc::Rc,
sync::{Arc, Mutex},
};
fn foo(n: impl DontCare<Output = i32>) {
let n = n.gimme_it();
println!("n = {}", n)
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(b);
foo(c);
foo(d);
}
trait DontCare {
type Output;
fn gimme_it(self) -> Self::Output;
}
impl DontCare for i32 {
type Output = Self;
fn gimme_it(self) -> Self::Output {
self
}
}
impl<T: DontCare> DontCare for Mutex<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
self.into_inner()
.expect("Lets first assume unwrap() will not panic")
.gimme_it()
}
}
impl<T: DontCare> DontCare for Rc<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
match Rc::try_unwrap(self) {
Ok(v) => v.gimme_it(),
_ => unreachable!("Lets first assume unwrap() will not panic"),
}
}
}
impl<T: DontCare> DontCare for Arc<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
match Arc::try_unwrap(self) {
Ok(v) => v.gimme_it(),
_ => unreachable!("Lets first assume unwrap() will not panic"),
}
}
}
The function signatures you've specified take ownership of the value. That will be highly painful, especially paired with any type that doesn't implement Copy.
There are a number of code paths that panic implicitly. I'm not a fan of baking in panics — I reserve that for algorithmic failures, not data-driven ones.
See also:
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
My answer is similar to Shepmaster's answer, but maybe a little more practical since it doesn't consume the argument to foo2 and it gives you a reference to the target instead of taking it out of the container.
I never have any luck implementing traits based on other traits so I didn't try to do that here.
use std::ops::Deref;
use std::rc::Rc;
use std::sync::{Arc, Mutex, MutexGuard};
fn foo(n: i32) {
println!("n = {}", n)
}
trait Holding<T> {
type Holder: Deref<Target = T>;
fn held(self) -> Self::Holder;
}
fn foo2<H: Holding<i32>>(x: H) {
let h = x.held();
println!("x = {}", *h);
}
impl<'a, T: 'a> Holding<T> for &'a T {
type Holder = &'a T;
fn held(self) -> Self::Holder {
self
}
}
impl<'a, T> Holding<T> for &'a Rc<T> {
type Holder = &'a T;
fn held(self) -> Self::Holder {
&**self
}
}
impl<'a, T> Holding<T> for &'a Mutex<T> {
type Holder = MutexGuard<'a, T>;
fn held(self) -> Self::Holder {
// this can panic
self.lock().unwrap()
}
}
impl<'a, T> Holding<T> for &'a Arc<Mutex<T>> {
type Holder = MutexGuard<'a, T>;
fn held(self) -> Self::Holder {
// this can panic
(*self).lock().unwrap()
}
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(*b);
foo(*(c.lock().unwrap()));
foo(*((*d).lock().unwrap()));
foo2(&a);
foo2(&b);
foo2(&c);
foo2(&d);
}
When attempting to answer this question, I wrote this code:
trait MyTrait {
type A;
type B;
}
trait WithFoo: MyTrait {
fn foo(a: Self::A) -> Self::B;
}
impl<T, U: MyTrait<A = T, B = T>> WithFoo for U {
fn foo(a: T) -> T {
a
}
}
struct S1;
impl MyTrait for S1 {
type A = u32;
type B = f32;
}
impl WithFoo for S1 {
fn foo<T>(a: Self::A) -> Self::B {
a as f32
}
}
struct S2;
impl MyTrait for S2 {
type A = u32;
type B = u32;
}
fn main() {
S1::foo(42);
S2::foo(42);
}
playground
This fails to compile with the following error:
error[E0119]: conflicting implementations of trait `WithFoo` for type `S1`:
--> src/main.rs:23:1
|
10 | impl<T, U: MyTrait<A = T, B = T>> WithFoo for U {
| ----------------------------------------------- first implementation here
...
23 | impl WithFoo for S1 {
| ^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S1`
According to these answers this error occurs even though type S1 doesn't fit the impl trait bounds when the compiler can't be sure that some future blanket impl would cause S1 to suddenly match the bounds.
However in this case it is impossible that S1 could ever implement MyTrait with A == B since it already implements MyTrait with A != B. Is the error a limitation of the current compiler implementation that might conceivably be lifted at some later point or is there something else I'm missing?
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.