In Swift I can attach extension methods to any of struct, enum or protocol(same with trait in Rust).
protocol Foo1 {
func method1() -> Int
}
extension Foo1 {
func method2() {
print("\(method1())")
}
}
Then all types conforming the protocol Foo1 now all have method2().
This is very useful to build "method chaining" easily.
How to do same in Rust? This doesn't work with an error.
struct Kaz {}
impl Foo for Kaz {}
trait Foo {
fn sample1(&self) -> isize { 111 }
}
impl Foo {
fn sample2(&self) {
println!("{}", self.sample1());
}
}
fn main() {
let x = Kaz {};
x.sample1();
x.sample2();
}
Here's the error.
warning: trait objects without an explicit `dyn` are deprecated
--> src/main.rs:13:6
|
13 | impl Foo {
| ^^^ help: use `dyn`: `dyn Foo`
|
= note: `#[warn(bare_trait_objects)]` on by default
error[E0599]: no method named `sample2` found for type `Kaz` in the current scope
--> src/main.rs:22:7
|
3 | struct Kaz {}
| ---------- method `sample2` not found for this
...
22 | x.sample2();
| ^^^^^^^ method not found in `Kaz`
error: aborting due to previous error
In Rust, you can use extension traits, that is a trait with a generic implementation for all types T that implement the base trait:
struct Kaz {}
impl Foo for Kaz {}
trait Foo {
fn sample1(&self) -> isize { 111 }
}
trait FooExt {
fn sample2(&self);
}
impl<T: Foo> FooExt for T {
fn sample2(&self) {
println!("{}", self.sample1());
}
}
fn main() {
let x = Kaz {};
x.sample1();
x.sample2();
}
Playground
Related
I'm running into an issue where the compiler seems unable to coerce the desired type by recursive deref-coersion. I have the following code:
use std::ops::Deref;
struct MyStruct<T> {
data: T
}
impl<T> Deref for MyStruct<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
pub trait MyTrait {
fn bar(&self);
}
impl<T> MyTrait for MyStruct<T> {
fn bar(&self) {}
}
fn foo<T: MyTrait>(arg: T) {
//
}
fn main() {
let data = Box::new(MyStruct { data: 42 });
foo(&data);
}
And I get the following error:
error[E0277]: the trait bound `&Box<MyStruct<{integer}>>: MyTrait` is not satisfied
--> src\bin\main.rs:36:9
|
36 | foo(&data);
| ^^^^^ the trait `MyTrait` is not implemented for `&Box<MyStruct<{integer}>>`
|
note: required by a bound in `foo`
--> src\bin\main.rs:30:11
|
30 | fn foo<T: MyTrait>(arg: T) {
| ^^^^^^^ required by this bound in `foo`
My expectation is that the compiler would be able to recursively deref Box<MyStruct> until it encountered a type that satisfied the trait requirement (MyTrait) for the argument.
How might I be able to achieve this without modifying the calling syntax of foo(&data)?
Given a struct that depends on a generic type parameter, can we define an associated function whose implementation depends on that type?
I'd like to pass a struct to a routine, but have the associated functions compute differently depending on the internal type. This routine also depends on the members in the struct, so I'd rather not move everything to a trait.
As an example, the following code attempts to define a different printme function depending on the type involved:
// Trait locked to a type
trait MyF64 {}
impl MyF64 for f64 {}
trait MyU32 {}
impl MyU32 for u32 {}
// Some kind of struct
struct Foo<T> {
t: T,
}
// Implementation for f64
impl<T> Foo<T>
where
T: MyF64,
{
fn printme(&self) {
println!("In a f64: {}", self.t);
}
}
// Implementation for u32
impl<T> Foo<T>
where
T: MyU32,
{
fn printme(&self) {
println!("In a u32: {}", self.t);
}
}
// Takes a foo
fn foo<T>(x: Foo<T>) {
foo.printme();
}
fn main() {
// Try both cases
foo(Foo { t: 1.2 });
foo(Foo { t: 12 });
}
This gives the compiler error:
error[E0592]: duplicate definitions with name `printme`
--> src/main.rs:17:5
|
17 | / fn printme(&self) {
18 | | println!("In a f64: {}", self.t);
19 | | }
| |_____^ duplicate definitions for `printme`
...
27 | / fn printme(&self) {
28 | | println!("In a u32: {}", self.t);
29 | | }
| |_____- other definition for `printme`
If I move the definition of printme into another trait, we have a similar, but different problem
// Trait locked to a type
trait MyF64 {}
impl MyF64 for f64 {}
trait MyU32 {}
impl MyU32 for u32 {}
// Some kind of struct
struct Foo<T> {
t: T,
}
// Trait for Foo
trait FooTrait {
fn printme(&self);
}
// Implementation for f64
impl<T> FooTrait for Foo<T>
where
T: MyF64,
{
fn printme(&self) {
println!("In a f64: {}", self.t);
}
}
// Implementation for u32
impl<T> FooTrait for Foo<T>
where
T: MyU32,
{
fn printme(&self) {
println!("In a u32: {}", self.t);
}
}
// Takes a foo
fn foo<T>(x: Foo<T>)
where
Foo<T>: FooTrait,
{
foo.printme();
}
fn main() {
// Try both cases
foo(Foo { t: 1.2 });
foo(Foo { t: 12 });
}
This gives the compiler error:
error[E0119]: conflicting implementations of trait `FooTrait` for type `Foo<_>`:
--> src/main.rs:28:1
|
18 | / impl<T> FooTrait for Foo<T>
19 | | where
20 | | T: MyF64,
21 | | {
... |
24 | | }
25 | | }
| |_- first implementation here
...
28 | / impl<T> FooTrait for Foo<T>
29 | | where
30 | | T: MyU32,
31 | | {
... |
34 | | }
35 | | }
| |_^ conflicting implementation for `Foo<_>`
Strictly speaking, we can fix this experiment by just adding a better trait to the types with:
// External libraries
use std::fmt::Display;
// Trait gives the name
trait MyTrait {
fn name(&self) -> String;
}
impl MyTrait for f64 {
fn name(&self) -> String {
"f64".to_string()
}
}
impl MyTrait for u32 {
fn name(&self) -> String {
"u32".to_string()
}
}
// Some kind of struct
struct Foo<T> {
t: T,
}
impl<T> Foo<T>
where
T: MyTrait + Display,
{
fn printme(&self) {
println!("In a {}: {}", self.t.name(), self.t);
}
}
// Takes a foo
fn foo<T>(x: Foo<T>)
where
T: MyTrait + Display,
{
x.printme();
}
fn main() {
// Try both cases
foo(Foo { t: 1.2 });
foo(Foo { t: 12 });
}
which gives the correct output:
In a f64: 1.2
In a u32: 12
That said, this code is relatively simple, so this kind of fix is easy. More generally, I have a struct that depends on user defined data. This data will necessarily have a different set of associated methods and it would be difficult to force each kind of data to have a common interface. However, the struct that depends on this data can assimilate this information well as long as it knows what kind of data it has. Theoretically, we could define two different structs that accept the two different kinds of data and have these structs implement a common interface. That said, I really want access to a common set of fields and would rather not have to define a number of setters and getters. Is there a better way to accomplish this?
Well, I suppose I should have thought about this longer, but the following accomplishes what I'd like without setters and getters:
// Trait locked to a type
trait Float {
fn bar(&self) -> String;
}
impl Float for f32 {
fn bar(&self) -> String {
"f32".to_string()
}
}
impl Float for f64 {
fn bar(&self) -> String {
"f64".to_string()
}
}
trait Int {
fn baz(&self) -> &'static str;
}
impl Int for i32 {
fn baz(&self) -> &'static str {
"i32"
}
}
impl Int for i64 {
fn baz(&self) -> &'static str {
"i64"
}
}
// Define all of the different implementations that we care to implement in Foo
enum MyTypes {
Float(Box <dyn Float>),
Int(Box <dyn Int>),
}
// Some kind of struct
struct Foo {
t : MyTypes,
}
// Implementation for f64
impl Foo {
fn printme(&self) {
match self.t {
MyTypes::Float(ref t) => {
println!("In a Float({})", t.bar());
}
MyTypes::Int(ref t) => {
println!("In an Int({})", t.baz());
}
}
}
}
// Takes a foo
fn foo(x : Foo) {
x.printme();
}
fn main() {
// Try both cases
foo(Foo { t : MyTypes::Float(Box::new(1.2_f32))});
foo(Foo { t : MyTypes::Int(Box::new(12_i64))});
}
Essentially, if we know that user defined data will come from a finite number of traits, we can wrap everything in an enum and then have the struct change its implementation depending on the kind of data that the user provides. This requires boxing the incoming user data based on the trait, which hides the underlying type appropriately.
I have a trait with generic type. I want to define a struct with a property which meets that trait and I want to implement a function in that struct that uses the function inside the trait:
pub trait Point<I> {
fn id(&self) -> I;
}
pub struct Connection<T> {
pub to: T,
}
impl<T: Point> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
pub fn main() {
struct SimplePoint;
impl Point<char> for SimplePoint {
fn id(&self) -> char {
return 'A';
}
}
let a = SimplePoint {};
let conn = Connection { to: a };
}
(playground)
If I try to run this code, I get an error:
error[E0243]: wrong number of type arguments: expected 1, found 0
--> src/main.rs:9:9
|
9 | impl<T: Point> Connection<T> {
| ^^^^^ expected 1 type argument
If I try add a generic type:
impl<T: Point<I>> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
Then I get this error:
error[E0412]: cannot find type `I` in this scope
--> src/main.rs:9:15
|
9 | impl<T: Point<I>> Connection<T> {
| ^ did you mean `T`?
If I try to define the type I:
impl<I, T: Point<I>> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
The compiler tells me that I is unconstrained:
error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:9:6
|
9 | impl<I, T: Point<I>> Connection<T> {
| ^ unconstrained type parameter
How should I declare the implementation of the is_connected_to function?
A generic type must be monomorphized: each generic type must be resolved as a concrete type. If there is no constraint, the compiler cannot know what is the concrete type you want. You must put the generic type in the function:
pub trait Point<I: PartialEq> {
fn id(&self) -> I;
}
pub struct Connection<T> {
pub to: T
}
impl<T> Connection<T> {
pub fn is_connected_to<I: PartialEq>(&self, point: T) -> bool
where
T: Point<I>
{
self.to.id() == point.id()
}
}
pub fn main() {
struct SimplePoint;
impl Point<char> for SimplePoint{
fn id(&self) -> char { return 'A' }
}
let a = SimplePoint {};
let conn = Connection {
to: a
};
}
I tried this:
trait T {}
fn f() -> impl T {
unimplemented!();
}
fn main() {
f();
}
But it gives this error:
error[E0277]: the trait bound `!: T` is not satisfied
--> src/main.rs:3:11
|
3 | fn f() -> impl T {
| ^^^^^^ the trait `T` is not implemented for `!`
|
= note: the return type of a function must have a statically known size
This compiles if a branch in f returns something:
struct S {}
trait T {}
impl T for S {}
fn f(a: u32) -> impl T {
if a == 0 {
panic!();
} else {
S {}
}
}
fn main() {
f(5);
}
This is a known issue.
The easy (cheating) answer is to implement your trait for !:
impl T for ! {}
You can see in the tracking issue for promoting ! to a type that much discussion has been around which traits to implement for a type.
There was also an RFC to implement traits automatically for !, but it was not accepted. This requires "implementing" any methods in the trait because another proposed RFC was also postponed:
trait T {
fn hello(&self) -> u32;
}
impl T for ! {
fn hello(&self) -> u32 {
*self
}
}
This question already has answers here:
Why doesn't Rust support trait object upcasting?
(5 answers)
Closed 6 years ago.
I'm trying to implement PartialEq in Rust for a trait that has subtypes, so that I can add them as boxed pointers to a container and later compare them.
Here's my scaled-down implementation:
use std::any::Any;
trait Foo: Any {}
struct Bar {}
impl Foo for Bar {}
struct Baz {}
impl Foo for Baz {}
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
let me = self as &Any;
let you = other as &Any;
if me.is::<Bar>() && you.is::<Bar>() {
true
} else if me.is::<Baz>() && you.is::<Baz>() {
true
} else {
false
}
}
}
fn main() {
let bar: Bar = Bar {};
let baz: Baz = Baz {};
let foo1: &Foo = &bar;
let foo2: &Foo = &baz;
println!("{:?}", foo1 == foo2);
}
Code example in Rust Playground.
When I build this, I get:
rustc 1.17.0-nightly (0648517fa 2017-02-03)
error: non-scalar cast: `&Foo + 'static` as `&std::any::Any + 'static`
--> <anon>:15:18
|
15 | let me = self as &Any;
| ^^^^^^^^^^^^
error: non-scalar cast: `&Foo + 'static` as `&std::any::Any + 'static`
--> <anon>:16:19
|
16 | let you = other as &Any;
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
which is confusing. Any ideas what I'm doing wrong here?
Edit: I don't believe this is a duplicate of Why doesn't Rust support trait object upcasting?, because what I'm trying to do is downcast using Any, not upcast.
Further Edit: Yes, this is a duplicate - sorry, I was thinking about what I was trying to do (downcast to the Bar and Baz types) rather than how I was doing that (upcasting to Any). However, that being said, I guess I still don't understand why the Any example, where they do this: let value_any = value as &Any; works, where mine doesn't. That being said, Joshua Entrekin did give a great answer.
Final Edit An, never mind, it's because I'm upcasting a trait rather than a type - Doh!. Thanks, everyone!
This is a duplicate of Why doesn't Rust support trait object upcasting? because you are trying to upcast from Foo to Any. If you add an as_any method to Foo and implement on it, this code can be made to work:
use std::any::Any;
trait Foo: Any {
fn as_any(&self) -> &Any;
}
impl<T: Any> Foo for T {
fn as_any(&self) -> &Any {
self
}
}
struct Bar {}
struct Baz {}
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
let me = self.as_any();
let you = other.as_any();
if me.is::<Bar>() && you.is::<Bar>() {
true
} else if me.is::<Baz>() && you.is::<Baz>() {
true
} else {
false
}
}
}
fn main() {
let bar: Bar = Bar {};
let baz: Baz = Baz {};
let foo1: &Foo = &bar;
let foo2: &Foo = &baz;
println!("{:?}", foo1 == foo2);
}
I show it here in the Playground.