How do I treat generics? - rust

I would like to calculate a factorial using generics, but I get an error in main.
My full code:
pub trait Body {
fn new() -> Self;
fn fact(&self, x: usize) -> usize {
match x {
1 => 1,
_ => x * self.fact(x - 1),
}
}
}
#[derive(Clone, Debug)]
pub struct RecursiveCall<T: Body> {
level: usize,
indicator: String,
n_repeat: usize,
body: T,
}
impl<T> RecursiveCall<T>
where T: Body
{
fn new(n_repeat: usize) -> RecursiveCall<T> {
RecursiveCall {
level: 0,
indicator: "- ".to_string(),
n_repeat: n_repeat,
body: <T as Body>::new(),
}
}
fn pre_trace(&self, fname: &str, arg: &usize) {
let args: String = arg.to_string();
println!("{}",
(vec![self.indicator.as_str(); self.level]).join("") +
self.level.to_string().as_str() + ":" + fname + "(" +
args.as_str() + ")");
}
fn post_trace(&self, fname: &str, arg: &usize, ret: &usize) {
println!("{}",
(vec![self.indicator.as_str(); self.level]).join("") +
self.level.to_string().as_str() + ":" + fname + "=" +
ret.to_string().as_str());
}
fn print_trace(&mut self) {
&self.pre_trace("fact", &self.n_repeat);
self.level += 1;
let ret = &self.body.fact(self.n_repeat);
self.level -= 1;
&self.post_trace("fact", &self.n_repeat, ret);
println!("Difference={}", &ret.to_string().as_str());
}
}
type B = Body;
fn main() {
let t = RecursiveCall::<B>::new();
}
This error occurs in main():
error: no associated item named `new` found for type `RecursiveCall<Body + 'static>` in the current scope
--> src/main.rs:61:13
|
61 | let t = RecursiveCall::<B>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the method `new` exists but the following trait bounds were not satisfied: `Body : std::marker::Sized`, `Body : Body`
= help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `new`, perhaps you need to implement one of them:
= help: candidate #1: `Body`
= help: candidate #2: `std::sys_common::thread_info::NewThread`
= help: candidate #3: `std::iter::ZipImpl`
error[E0277]: the trait bound `Body + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:61:13
|
61 | let t = RecursiveCall::<B>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Body + 'static`
|
= note: `Body + 'static` does not have a constant size known at compile-time
= note: required by `RecursiveCall`
error[E0277]: the trait bound `Body + 'static: Body` is not satisfied
--> src/main.rs:61:13
|
61 | let t = RecursiveCall::<B>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Body` is not implemented for `Body + 'static`
|
= note: required by `RecursiveCall`
error[E0038]: the trait `Body` cannot be made into an object
--> src/main.rs:61:13
|
61 | let t = RecursiveCall::<B>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Body` cannot be made into an object
|
= note: method `new` has no receiver

The key to the answer is in this note from the compiler:
note: the method new exists but the following trait bounds were not satisfied: Body : std::marker::Sized, Body : Body
You've defined B as a type alias for Body, so the names B and Body both mean the same thing in your program (at least in this module).
When you define a trait, the compiler also defines a type with the same name. However, that type cannot be instantiated directly (unlike a class in C++/C#/Java/etc.). Yet, that's exactly what you're trying to do!
The trait bound Body : std::marker::Sized is not satisfied because Body, being the type defined by the compiler corresponding to the trait of the same name, is an unsized type. Unsized types can only be used in pointers and references (e.g. &Body, Box<Body>, etc.).
The trait bound Body : Body is not satisfied because your trait is not object-safe. It's not object-safe because the method new doesn't have a self parameter (this is what the compiler means in the last note: method `new` has no receiver).
Normally, you would define a struct or an enum and implement the trait for that type, and then use that type when instantiating RecursiveCall. Try replacing type B = Body; with the following:
struct B;
impl Body for B {
fn new() -> B {
B
}
}

Related

Documentation regarding using traits for associated types

I'm unclear as to why traits are usable within the RHS of the type syntax for what I recognize as an associated type. I searched through the language reference and could not find it, but am not sure if I did not find it due to lack of familiarity/understanding, or because it's as of yet undocumented.
Here is a playground with the same code.
trait ATrait {
fn a(&self) -> f64;
}
trait BTrait {
fn b(&self) -> f64;
}
trait Container {
// Why can we just use 'traits'?
type Item: ATrait + BTrait;
fn describe_container() -> i32;
}
struct ContainerType;
impl Container for ContainerType {
type Item = ItemType;
fn describe_container() -> i32 {
42
}
}
struct ItemType;
impl ATrait for ItemType {
fn a(&self) -> f64 {
3.141
}
}
impl BTrait for ItemType {
fn b(&self) -> f64 {
2.718
}
}
fn main() {
let _ct = ContainerType {};
ContainerType::describe_container();
}
It appears in the reference here. Specifically, AssociatedItem refers to TypeAlias, and it includes ( : TypeParamBounds )? and mentions (at the end of the page) that:
A type alias with TypeParamBounds may only specified when used as an associated type in a trait.
These bounds mean that for every type that implement the trait, the type provided for this associated type will have to implement the mentioned traits. In your example, ItemType, specified as Container::Item for ContainerType, must implement ATrait and BTrait, or errors will be emitted:
error[E0277]: the trait bound `ItemType: BTrait` is not satisfied
--> src/main.rs:17:17
|
17 | type Item = ItemType;
| ^^^^^^^^ the trait `BTrait` is not implemented for `ItemType`
|
note: required by a bound in `Container::Item`
--> src/main.rs:11:25
|
11 | type Item: ATrait + BTrait;
| ^^^^^^ required by this bound in `Container::Item`
error[E0277]: the trait bound `ItemType: ATrait` is not satisfied
--> src/main.rs:17:17
|
17 | type Item = ItemType;
| ^^^^^^^^ the trait `ATrait` is not implemented for `ItemType`
|
note: required by a bound in `Container::Item`
--> src/main.rs:11:16
|
11 | type Item: ATrait + BTrait;
| ^^^^^^ required by this bound in `Container::Item`

Why does `|_| 1` not meet lifetime requirements

I have the following trait and generic implementation for Fn:
trait Provider<'a> {
type Out;
fn get(&'a self, state: &State) -> Self::Out;
}
impl<'a, F, T> Provider<'a> for F
where
F: Fn(&State) -> T,
{
type Out = T;
fn get(&'a self, state: &State) -> T {
self(state)
}
}
Now, I have some code that wants a for<'a> Provider<'a, Out = usize>. However, the most simple closure, |_| 1, does not qualify and instead provides this error message which I don't understand:
fn assert_usize_provider<P>(_: P)
where
P: for<'a> Provider<'a, Out = usize>,
{
}
fn main() {
assert_usize_provider(|_| 1);
}
error[E0308]: mismatched types
--> src/main.rs:27:5
|
27 | assert_usize_provider(|_| 1);
| ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `FnOnce<(&State,)>`
found type `FnOnce<(&State,)>`
note: this closure does not fulfill the lifetime requirements
--> src/main.rs:27:27
|
27 | assert_usize_provider(|_| 1);
| ^^^^^
note: the lifetime requirement is introduced here
--> src/main.rs:22:29
|
22 | P: for<'a> Provider<'a, Out = usize>,
| ^^^^^^^^^^^
Playground link
Can someone explain what that error message means and how to get this code working?
I don't know why inference does not work in this case but you can add type annotation to get the code working.
assert_usize_provider(|_ : &State| 1);

Cast struct object to dynamic trait object

This is a simpler version of my code:
type Res = Result<(), Box<dyn std::error::Error + Send + Sync>>;
// defined before-hand
pub trait Attr {
fn method(&self) -> Res;
}
// a struct, a block of code provided by user
// which is unknown by far
pub struct S;
// the trait implemented for provided struct
// user does this manually
// which is unknown by far
impl Attr for S {
fn method(&self) -> Res {
Ok(())
}
}
// in order to use the struct and its implemented method
// a possible way may be cast struct type to dynamic trait object
type Item = dyn Fn(&dyn Attr) -> Res;
pub fn use_method(f: &Item) {}
fn main() {
// casting happens here
// and do this job in macro, here is simplified version
let m = &(<S as Attr>::method) as &Item;
use_method(m);
}
It is required to tackle a struct, a block of code and its implementation both of which are unknown and provided by user. A rough direction may be using a trait as dynamic trait bounds which converted from struct object, but the compiler complain:
error[E0631]: type mismatch in function arguments
--> src/main.rs:30:13
|
4 | fn method(&self) -> Res;
| ------------------------ found signature of `for<'r> fn(&'r S) -> _`
...
30 | let m = &(<S as Attr>::method) as &Item;
| ^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r (dyn Attr + 'r)) -> _`
|
= note: required for the cast to the object type `dyn for<'r> Fn(&'r (dyn Attr + 'r)) -> std::result::Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>`
How can I get it done? Is there any other way?

How to return an iterator over the keys of a HashMap from a trait implementation?

I'm trying to build a simple graph library in Rust. There is a trait Graph that any graph must implement. This trait has only one function at the moment, nodes, which allows iteration of the graph's nodes using a for-in loop.
An implementation of Graph, MapGraph, is a lightweight wrapper around a HashMap. MapGraph must implement the Graph trait method nodes. I'm having problems getting this to work.
Here's the code for Graph:
pub trait Graph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item = &N>>;
}
And here's the code for MapGraph:
use std::collections::HashMap;
use crate::rep::Graph;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item=&N>> {
let keys = self.map.keys();
Box::new(keys)
}
}
The compiler gives this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:19:29
|
19 | let keys = self.map.keys();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn nodes(&self) -> Box<dyn Iterator<Item = &N>> {
19 | | let keys = self.map.keys();
20 | |
21 | | Box::new(keys)
22 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:19:20
|
19 | let keys = self.map.keys();
| ^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
I've found other references to this error, but those cases don't seem to look like the one I have here.
I'm using Box because the Graph trait has a function that itself returns a trait. What is the correct way to return an Iterator (or any other trait)? gives this approach as one option, and I haven't been able to implement any of the the others. If there's another way to do this, that would be fine.
What are my options for resolving this specific problem?
It works if you explicitly specify that the trait object (dyn Iterator) that you are returning contains references that are tied to the lifetime of self.
Without adding this bound, the compiler cannot infer from the function signature that the iterator cannot be used after self is moved or destroyed. Because the compiler cannot infer this, it cannot safely use self.map.keys() in the function's output.
Working example with this bound added:
pub trait Graph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a>;
}
use std::collections::HashMap;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>,
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a> {
let keys = self.map.keys();
Box::new(keys)
}
}
Playground
I had thought that a bound of Item = &'a N would also be required, but I guess that's already covered by the "+ 'a"...
N.B. that to make sense of an error like:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
you have to understand that the compiler, for ergonomic reasons, automatically adds a + 'static lifetime qualifier to any unqualified trait object. This means that an unqualified Box<dyn MyTrait> is transformed by the compiler into a Box<(dyn MyTrait + 'static)>, which in turn means that the object cannot contain any references except those that last for the lifetime of the entire program.
With this in mind you can see why self.map.keys() does not fit this strict bound, and a more specific explicit bound is required.

Sharing a struct with trait objects as properties across threads

I have the code below. With the commented out parts, it's working. When I uncomment the parts it does not compile anymore.
How can I adjust the commented parts to make them work, i.e., I want to make threads access the expression tree simultaneously.
When I try it, the compiler starts with errors about thread safeness.
I read the Rust book and know C/C++, but didn't understood everything about Rust type system and semantics yet.
use std::thread;
use std::sync::Arc;
pub trait Expr {
fn run(&self) -> i32;
}
pub struct ConstantExpr {
n: i32,
}
impl ConstantExpr {
pub fn new(n: i32) -> Self {
Self { n }
}
}
impl Expr for ConstantExpr {
fn run(&self) -> i32 {
self.n
}
}
pub struct AddExpr {
expr1: Box<Expr>,
expr2: Box<Expr>,
}
impl AddExpr {
pub fn new(expr1: Box<Expr>, expr2: Box<Expr>) -> Self {
Self { expr1, expr2 }
}
}
impl Expr for AddExpr {
fn run(&self) -> i32 {
self.expr1.run() + self.expr2.run()
}
}
struct Container {
x: i32,
cached_expr: Arc<Expr>,
}
impl Container {
fn new() -> Self {
Self {
x: 0,
cached_expr: Arc::new(AddExpr::new(
Box::new(ConstantExpr::new(10)),
Box::new(ConstantExpr::new(1)),
)),
}
}
}
fn main() {
let container = Arc::new(Container::new());
let container1 = Arc::clone(&container);
/*
let thread1 = thread::spawn(move || {
println!("thread1: {}", container1.x);
println!("thread1: {}", container1.cached_expr.run());
});
*/
println!("main: {}", container.x);
println!("main: {}", container.cached_expr.run());
//thread1.join().unwrap();
}
The error:
error[E0277]: the trait bound `Expr + 'static: std::marker::Send` is not satisfied
--> src/main.rs:64:19
|
64 | let thread1 = thread::spawn(move || {
| ^^^^^^^^^^^^^ `Expr + 'static` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `Expr + 'static`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Expr + 'static>`
= note: required because it appears within the type `Container`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Container>`
= note: required because it appears within the type `[closure#src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]`
= note: required by `std::thread::spawn`
error[E0277]: the trait bound `Expr + 'static: std::marker::Sync` is not satisfied
--> src/main.rs:64:19
|
64 | let thread1 = thread::spawn(move || {
| ^^^^^^^^^^^^^ `Expr + 'static` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `Expr + 'static`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Expr + 'static>`
= note: required because it appears within the type `Container`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Container>`
= note: required because it appears within the type `[closure#src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]`
= note: required by `std::thread::spawn`
I find the error message pretty straightforward:
the trait std::marker::Send is not implemented for Expr + 'static
required because of the requirements on the impl of std::marker::Send for std::sync::Arc<Expr + 'static>
required because it appears within the type Container
required because of the requirements on the impl of std::marker::Send for std::sync::Arc<Container>
required because it appears within the type [closure#src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]
required by std::thread::spawn
You are trying to move your Arc<Container> to another thread, but it contains an Arc<Expr + 'static>, which cannot be guaranteed to be safely sent (Send) or shared (Sync) across threads.
Either add Send and Sync as supertraits to Expr:
pub trait Expr: Send + Sync { /* ... */ }
Or add them as trait bounds to your trait objects:
pub struct AddExpr {
expr1: Box<Expr + Send + Sync>,
expr2: Box<Expr + Send + Sync>,
}
impl AddExpr {
pub fn new(expr1: Box<Expr + Send + Sync>, expr2: Box<Expr + Send + Sync>) -> Self {
Self { expr1, expr2 }
}
}
struct Container {
x: i32,
cached_expr: Arc<Expr + Send + Sync>,
}
See also:
How can I share references across threads?
Multithreaded application fails to compile with error-chain
Is there any way to implement the Send trait for ZipFile?
How do I share a generic struct between threads using Arc<Mutex<MyStruct<T>>>?

Resources