Lets suppose I have a trait
trait A {
fn new() -> Self where Self : Sized;
fn foo(&self) -> i32;
}
struct B {
data : i32
}
impl A for B {
fn new() -> Self {
B {data : 42}
}
fn foo(&self) -> i32 {
self.data
}
}
Now I can use Box<dyn A>, I just do not have the new() method available.
And when I have a generic T : A, I can do T::new(). So I can use A as a trait object (without the functions which would prevent this) and I can use it in a templated code and use all functions on it.
My question is, is it possible to get this behavior when having for example Clone as supertrait?
In the dyn A case A does not implement Clone. In the generic case is does.
You can do like that:
trait A {
fn new() -> Self where Self : Sized;
fn foo(&self) -> i32;
}
#[derive(Clone)]
struct B {
data : i32
}
impl A for B {
fn new() -> Self {
B {data : 42}
}
fn foo(&self) -> i32 {
self.data
}
}
fn make_clone<T: Clone + A>(toc: &T) -> T {
dbg!(toc.foo());
toc.clone()
}
fn main() {
let b = B{data: 0};
make_clone(&b);
}
so you can access A method and theClone supertrait from make_clone, you can obviously do the same thing with a supertrait instead of a generic method
Related
I'm a newbie with Rust and I bumped into some obstacles when dealing with closures, either when returning them from functions and or methods, either when I need to store them as struct fields.
Let's start with what is working:
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo1 = Foo { foo: |a| a + 1 };
let foo2 = Foo { foo: build_func(2) };
let foo_func = build_func(3);
let foo3 = Foo { foo: foo_func };
}
This works as expected and the type of the closure that is built outside the struct is properly matched with the generic of Foo.
I wanted to achieve the same, but by hiding the creation of the closure simply by moving it inside the impl of Foo itself.
I tested these alternatives, but none of theme compiles:
struct Foo2<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
struct Foo3<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo3<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = |a| a + 1;
Self { foo }
}
}
struct Foo4<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo4<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> F {
move |a| a + b
}
}
struct Foo5<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo5<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
I understand that each closure has its own opaque and distinct type, but then I don't understand why on the other hand the initial implementation of Foo works then.
By reading the accepted answer here I seem to understand that the only option, in this case, would be to box the closure, but I still don't have a full understanding.
By combining boxed closure and trait aliases (I know it's not the "real" trait aliasing) I came up with this:
trait Func: Fn(usize) -> usize {}
impl<T> Func for T where T: Fn(usize) -> usize {}
struct Foo6 {
pub foo: Box<dyn Func>,
}
impl Foo6 {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Func {
move |a| a + b
}
}
fn main() {
let foo = Foo6::new();
println!("{}", (foo.foo)(1));
}
But I'm wondering whether it's possible to obtain an unboxed version.
The problem in this code:
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
is that to call it, the user code would need to write something like this:
let foo2 = <Foo2<?>>::new();
And specify some type there. Even if the type is not typed explicitly, it should be resolved there (type omission is mostly syntactic sugar). But the type of the stored value is decided inside that function, in the call to build_func(1), so the user has no type to use there and that function cannot be called.
My advice is to just write a free function:
fn new_foo2() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
Now the generic type is an impl in the return type of the function, that is an special opaque generic decided by the code of the function. So this works.
If you really, really want to write Foo2::new you can write the function implementation inside a dummy non-generic impl Foo2 block. Usually that would be impl Foo2<()> but the type () does not satisfies your constraints, but you can use any other dummy type that does:
impl Foo2<fn(usize)->usize> {
fn new() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
}
(Note that this new() does not return Self because the generic type is not correct.)
And now you can at least write:
let foo2 = Foo2::new();
The difference here is that you're returning Self from new(). Inside impl<F> Foo<F>, Self refers to Foo<F>. And F is a generic parameter - you cannot build a closure of type F, because it's a type your caller decides what it is, not you.
Your first version works because it tells the compiler "I will return some type implementing Fn; I'll leave it to you infer what exactly". On the other hand, the second versions are all "given any type F implementing Fn, I'll give you an instance of that type". That is of course impossible.
Instead you want the compiler to infer the used type here, too. The best solution will be to use impl Trait here, too. But impl Trait in positions other than return type is unstable. It will look like (playground):
#![feature(type_alias_impl_trait)]
type InnerFn = impl Fn(usize) -> usize;
struct Foo {
pub foo: InnerFn,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> InnerFn {
move |a| a + b
}
}
Another (quite hacky) solution is to have a generic parameter, but not use it and instead use impl Trait in new(). To not require the caller to specify the redundant parameter (since it can't be inferred anymore as it's unused), we can use a marker type, usually (). This requires us to remove the F: Fn(usize) -> usize bound from the struct and put it only on the impl, however this is a good style anyway (playground):
struct Foo<F> {
pub foo: F,
}
impl Foo<()> {
fn new() -> Foo<impl Fn(usize) -> usize> {
let foo = Self::build_func(1);
Foo { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
The last solution is indeed to box the closure, but you don't need a new trait for that - you can use Fn directly (playground):
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
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![];
I'm struggling to understand the nuances of the ? operator. Take the following code:
link to playground
use std::{error::Error as StdError, fmt};
#[derive(Debug)]
struct MyError(Box<dyn StdError>);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for MyError{}
impl From<Box<dyn StdError>> for MyError {
fn from(err: Box<dyn StdError>) -> Self {
MyError(err)
}
}
#[derive(Debug)]
struct RandomErr(String);
impl fmt::Display for RandomErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for RandomErr{}
fn no_custom() -> Result<(), Box<dyn StdError>> {
Err(RandomErr("hello there".to_owned()))?
}
// This fails to compile
fn custom() -> Result<(), MyError> {
Err(RandomErr("hello there".to_owned()))?
}
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
Nope. There is no transitivity in From (or any trait, as far as I know). Rustc generally does what you tell it and no more to avoid problems like combinatory explosions in trait resolution.
So that C: From<B> and B: From<A> does not imply / translate to C: From<A>, you can write that reduced case and will hit E0277 (trait not satisfied):
struct A;
struct B;
struct C;
impl From<A> for B {
fn from(a: A) -> Self { B }
}
impl From<B> for C {
fn from(b: B) -> Self { C }
}
fn main() {
let _: C = From::from(A);
}
With Rust traits, I can express a Monoid type class (forgive me for the naming of the methods):
trait Monoid {
fn append(self, other: Self) -> Self;
fn neutral() -> Self;
}
Then, I can also implement the trait for strings or integers:
impl Monoid for i32 {
fn append(self, other: i32) -> i32 {
self + other
}
fn neutral() -> Self { 0 }
}
However, how could I now add another implementation on i32 for the multiplication case?
impl Monoid for i32 {
fn append(self, other: i32) -> i32 {
self * other
}
fn neutral() { 1 }
}
I tried something like what is done in functional but that solution seems to rely on having an additional type parameter on the trait instead of using Self for the elements, which gives me a warning.
The preferred solution would be using marker traits for the operations - something I also tried but didn't succeed in.
The answer, as pointed out by #rodrigo, is to use marker structs.
The following example shows a working snippet: playground
trait Op {}
struct Add;
struct Mul;
impl Op for Add {}
impl Op for Mul {}
trait Monoid<T: Op>: Copy {
fn append(self, other: Self) -> Self;
fn neutral() -> Self;
}
impl Monoid<Add> for i32 {
fn append(self, other: i32) -> i32 {
self + other
}
fn neutral() -> Self {
0
}
}
impl Monoid<Mul> for i32 {
fn append(self, other: i32) -> i32 {
self * other
}
fn neutral() -> Self {
1
}
}
pub enum List<T> {
Nil,
Cons(T, Box<List<T>>),
}
fn combine<O: Op, T: Monoid<O>>(l: &List<T>) -> T {
match l {
List::Nil => <T as Monoid<O>>::neutral(),
List::Cons(h, t) => h.append(combine(&*t)),
}
}
fn main() {
let list = List::Cons(
5,
Box::new(List::Cons(
2,
Box::new(List::Cons(
4,
Box::new(List::Cons(
5,
Box::new(List::Cons(-1, Box::new(List::Cons(8, Box::new(List::Nil))))),
)),
)),
)),
);
println!("{}", combine::<Add, _>(&list));
println!("{}", combine::<Mul, _>(&list))
}
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.