Trait as generic parameter to struct object intialization - rust

I have this struct:
use sp_runtime::traits::Block;
struct Bar<T: Block> {
e1: Vec<T>,
}
impl<T: Block> Bar<T> {
pub fn new() -> Self {
Bar { e1: Vec::new() }
}
}
Where Block is from the sp_runtime crate.
In main:
fn main() {
let var_1 = Bar::<Block>::new();
}
Full Code
This code throws compilation error that trait can't be made into an object. I'm new to Rust, much of online solution haven't addressed this issue. Kindly let me know how to get around initialization of bar object.

Your confusion likely stems from the fact that the sp_runtime crate has two items called Block. One is the trait sp_runtime::traits::Block and the other is a struct, sp_runtime::generic::Block, which implements that trait.
Traits can be used as a constraint on a type parameter, but they cannot be used as a type argument.
So, in your definition of Bar<T>, you can constrain T with sp_runtime::traits::Block, but when you construct an instance of Bar<T>, T needs to be the struct instead.
use sp_runtime::traits::Block;
struct<T: Block> Bar {
e1: Vec<T>,
}
impl<T: Block> Bar<T> {
pub fn new() -> Self {
Bar {
e1: Vec::new(),
}
}
}
fn main() {
use sp_runtime::generic::Block;
let var_1 = Bar::<Block>::new();
}
However, given that this is the only implementation of the trait in the crate, you can just avoid mentioning the trait altogether and use the concrete struct type (unless you plan on implementing it yourself or depending on implementations from other crates):
use sp_runtime::generic::Block;
struct Bar{
e1 : Vec<Block>,
}
impl Bar {
pub fn new() -> Self{
Bar {
e1: Vec::new(),
}
}
}
fn main() {
let var_1 = Bar::new();
}

Related

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

How to avoid orphan rules for repr transparent wrappers

My problem is I want to have a transparent wrapper and implemented Into<underlying> for it. Unfortunately, rust's orphan rules forbid it. Here is a simple example:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> Into<T> for MyWrapper<T> {
fn into(self) -> T {
self.0
}
}
The question is is there any way I can implement it? I'm using macro to generate impl for all types I'm currently using but it looks very awkward and dirty.
You can implement the Deref trait instead. The Deref docs contain the following example which is almost identical to your code:
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
You can implement it in a regular impl block:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> MyWrapper<T> {
pub fn into(self) -> T {
self.0
}
}
fn main() {
let wrapped : MyWrapper<f32> = MyWrapper::<f32>(3.4f32);
let unwrapped : f32 = wrapped.into();
println!("{}", unwrapped);
}

Why sized trait is required for a builder function to generate Rc<T>?

This code works fine (playground):
use std::rc::Rc;
trait Foo {
fn foo(&self);
}
struct Bar<T> {
v: Rc<T>,
}
impl<T> Bar<T> where
T: Foo {
fn new(rhs: Rc<T>) -> Bar<T> {
Bar{v: rhs}
}
}
struct Zzz {
}
impl Zzz {
fn new() -> Zzz {
Zzz{}
}
}
impl Foo for Zzz {
fn foo(&self) {
println!("Zzz foo");
}
}
fn make_foo() -> Rc<Foo> {
Rc::new(Zzz{})
}
fn main() {
let a = Bar::new(Rc::new(Zzz::new()));
a.v.as_ref().foo()
}
but if I make a wrapper to generate Rc like below, the compiler complains about missing sized trait (playground)
fn make_foo() -> Rc<dyn Foo> {
Rc::new(Zzz::new())
}
fn main() {
let a = Bar::new(make_foo());
a.v.as_ref().foo()
}
in both cases, Bar::new received parameters with same type Rc, why the rust compiler reacts different?
By default, all type variables are assumed to be Sized. For example, in the definition of the Bar struct, there is an implicit Sized constraint, like this:
struct Bar<T: Sized> {
v: Rc<T>,
}
The object dyn Foo cannot be Sized since each possible implementation of Foo could have a different size, so there isn't one size that can be chosen. But you are trying to instantiate a Bar<dyn Foo>.
The fix is to opt out of the Sized trait for T:
struct Bar<T: ?Sized> {
v: Rc<T>,
}
And also in the context of the implementations:
impl<T: ?Sized> Bar<T>
where
T: Foo
?Sized is actually not a constraint, but relaxing the existing Sized constraint, so that it is not required.
A consequence of opting out of Sized is that none of Bar's methods from that impl block can use T, except by reference.

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.

Implementing Rust traits cause struct to not be found

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.

Resources