Reading The Reference here: https://doc.rust-lang.org/reference/items/traits.html
#![allow(unused)]
fn main() {
use std::rc::Rc;
// Examples of non-object safe traits.
trait NotObjectSafe {
const CONST: i32 = 1; // ERROR: cannot have associated const
fn foo() {} // ERROR: associated function without Sized
fn returns(&self) -> Self; // ERROR: Self in return type
fn typed<T>(&self, x: T) {} // ERROR: has generic type parameters
fn nested(self: Rc<Box<Self>>) {} // ERROR: nested receiver not yet supported
}
struct S;
impl NotObjectSafe for S {
fn returns(&self) -> Self { S }
}
let obj: Box<dyn NotObjectSafe> = Box::new(S); // ERROR
}
I want to ask about this:
fn foo() {} // ERROR: associated function without Sized
I am making a proc-macro for get info about an enum.
pub trait EnumReflexion {
/// Returns the identifier of the enum type as an &str
fn enum_name<'a>() -> &'a str;
/// Returns an [`my_proj::my_crate::EnumInfo`] entity that contains
/// runtime reflexive info about `Self`.
fn enum_info<'a>() -> EnumInfo<'a>;
}
Brief piece of the impl on the macro:
let quote = quote! {
impl my_proj::my_crate::EnumReflexion for #ty {
fn enum_name<'a>() -> &'a str {
#ty_str
}
fn enum_info<'a>() -> EnumInfo<'a> {
#enum_info
}
}
};
I can compile my code perfectly fine, and it passes tests like this:
#[test]
fn get_enum_name() {
let variant = EnumMock::A;
assert_eq!("EnumMockd", EnumMock::enum_name());
}
#[derive(EnumInfo)]
enum EnumMock {
A,
B
}
Did that restriction of Sized in associated functions on traits get dropped? Or am I missing something?
Related
I need to create my own string type for easily porting NodeJS functionalities to Rust. I want to implement indexing with Range but I'm getting error at fn index():
/// Scalar Value string type.
#[derive(Clone, PartialEq, PartialOrd)]
pub struct SvStr {
m_chars: Vec<char>,
}
impl SvStr {
pub fn slice(&self, mut from: i64, mut to: i64) -> SvStr {
from = i64::max(0, from);
from = i64::min(from, self.len());
to = i64::max(0, to);
to = i64::min(to, self.len());
SvStr { m_chars: self.m_chars[(from as usize)..(to as usize)].to_vec() }
}
}
impl Index<&dyn SvStrSliceIndex> for SvStr {
type Output = SvStr;
fn index(&self, index: &dyn SvStrSliceIndex) -> &Self::Output {
// ERROR in following line!
// cannot return reference to temporary value
// returns a reference to data owned by the current function rustc E0515
// lib.rs(89, 10): temporary value created here
&self.slice(index.from_idx(), index.to_idx())
}
}
pub trait SvStrSliceIndex {
fn from_idx(&self) -> i64;
fn to_idx(&self) -> i64;
}
I tried to move code from SvStr's fn slice() to std::ops::Index's fn index() and I still get the same error. Any idea?
I have a trait with generic type parameter. I want to put different objects that implements this trait in a collection. Object have different type parameters.
When I do it, compiler tells me that I need to specify generic type parameter. I actually don't need this generic type information for my case, so some kind of wildcard would work for me. Let me show the code, as it shows my intention better:
trait Test<T> {
fn test(&self) -> T;
}
struct Foo;
struct Bar;
impl Test<i64> for Foo {
fn test(&self) -> i64 {
println!("foo");
42
}
}
impl Test<String> for Bar {
fn test(&self) -> String {
println!("bar");
"".to_string()
}
}
fn main() {
// I'm not going to invoke test method which uses generic type parameter.
// So some kind of wildcard would work for me.
// But underscore is not wildcard and this does not compile.
let xs: Vec<Box<dyn Test<_>>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}
The error is:
error[E0277]: the trait bound `Bar: Test<i64>` is not satisfied
--> src/main.rs:24:57
|
24 | let xs: Vec<Box<dyn Test<_>>> = vec![Box::new(Foo), Box::new(Bar)];
| ^^^^^^^^^^^^^ the trait `Test<i64>` is not implemented for `Bar`
|
= help: the following implementations were found:
<Bar as Test<std::string::String>>
= note: required for the cast to the object type `dyn Test<i64>`
I understand why compiler gives me this error: I put Foo first and it has i64 as a type parameter. After that compiler expects only i64 as a type parameter. But is there a way to workaround this?
I think you can not make it work exactly like this.
Your options to achieve a similar result are to either have your elements implement another non generic trait that you then add to your Vec if you do not know ahead of time which types for T are ultimately possible i.e. the trait is part of your public API and other crates are expected to implement it for their own types T.
trait NonGenericTest {}
trait Test2<T> : NonGenericTest {
fn test(&self) -> T;
}
impl NonGenericTest for Foo{}
impl NonGenericTest for Bar{}
impl Test2<i64> for Foo {
fn test(&self) -> i64 {
println!("foo");
42
}
}
impl Test2<String> for Bar {
fn test(&self) -> String {
println!("bar");
"".to_string()
}
}
fn main() {
let xs: Vec<Box<dyn NonGenericTest>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}
Or if you know all possible types of T ahead of time you could change the T in your trait to an enum that contains all the types you want to support here:
enum TestResult {
ResultI64(i64),
ResultString(String),
}
trait Test {
fn test(&self) -> TestResult;
}
struct Foo;
struct Bar;
impl Test for Foo {
fn test(&self) -> TestResult {
println!("foo");
TestResult::ResultI64(42)
}
}
impl Test for Bar {
fn test(&self) -> TestResult {
println!("bar");
TestResult::ResultString("".to_string())
}
}
fn main(){
let xs: Vec<Box<dyn Test>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}
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>)
When I implement a trait on a struct in Rust it's causing the struct type not to be found. First, the working code:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeStruct {
fn new() -> Box<SomeStruct> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
Here the SomeTrait trait isn't being used. Everything works. If I now change the impl of SomeStruct to implement SomeTrait:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeTrait for SomeStruct {
fn new() -> Box<SomeTrait> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
I get the error:
trait.rs:21:13: 21:28 error: failed to resolve. Use of undeclared module `SomeStruct`
trait.rs:21 let obj = SomeStruct::new();
^~~~~~~~~~~~~~~
trait.rs:21:13: 21:28 error: unresolved name `SomeStruct::new`.
trait.rs:21 let obj = SomeStruct::new();
What am I doing wrong? Why is SomeStruct suddenly missing? Thanks!
At the moment, associated functions (non-method functions) in traits are called via the trait, i.e. SomeTrait::new(). However, if you just write this, the compiler cannot work out which impl you're using, as there's no way to specify the SomeStruct information (it only works if the special Self type is mentioned in the signature somewhere). That is, the compiler needs to be able to work out which version of new should be called. (And this is required; they could have very different behaviour:
struct Foo;
impl SomeTrait for Foo {
fn new() -> Box<SomeTrait> { box Foo as Box<SomeTrait> }
}
struct Bar;
impl SomeTrait for Bar {
fn new() -> Box<SomeTrait> {
println!("hello")
box Bar as Box<SomeTrait>
}
}
Or something more dramatic than just printing.)
This is a language hole that will be filled by UFCS. For the moment, you need to use the dummy-Self trick:
trait SomeTrait {
fn new(_dummy: Option<Self>) -> Box<SomeTrait>;
...
}
which is then called like SomeTrait::new(None::<SomeStruct>).
However, I question why you are returning a boxed object from a constructor. This is rarely a good idea, it's normally better to just return the plain type directly, and the user can box it if necessary, that is,
trait SomeTrait {
fn new() -> Self;
...
}
(NB. this signature mentions Self and thus the Option trick above isn't required.)
Sidenote: the error message is rather bad, but it just reflects how these methods are implemented; an associated function in an impl Foo is very similar to writing mod Foo { fn ... }. You can see it differ by forcing the compiler to create that module:
struct Foo;
impl Foo {
fn bar() {}
}
fn main() {
Foo::baz();
}
prints just
<anon>:7:5: 7:13 error: unresolved name `Foo::baz`.
<anon>:7 Foo::baz();
^~~~~~~~
i.e. the Foo "module" exists.
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.