I am writing a basic binary tree structure and I want to display a node. It seems that Rust has trouble displaying a generic type, and I get this error:
error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
--> src/main.rs:55:60
|
55 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
|
= help: consider adding a `where T: std::fmt::Display` bound
= note: required by `std::fmt::Display::fmt`
error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
--> src/main.rs:62:60
|
62 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
|
= help: consider adding a `where T: std::fmt::Display` bound
= note: required by `std::fmt::Display::fmt`
Here's the full code, including the iterators
struct Node<T> {
data: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
struct NodeIterator<T> {
nodes: Vec<Node<T>>,
}
struct Tree<T> {
root: Option<Node<T>>,
}
impl<T> Node<T> {
pub fn new(value: Option<T>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>)
-> Node<T> {
Node {
data: value.unwrap(),
left: left,
right: right,
}
}
pub fn insert(&mut self, value: T) {
println!("Node insert");
match self.left {
Some(ref mut l) => {
match self.right {
Some(ref mut r) => {
r.insert(value);
}
None => {
self.right = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
None => {
self.left = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
}
impl<T> std::fmt::Display for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}
impl<T> std::fmt::Debug for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}
impl<T> Iterator for NodeIterator<T> {
type Item = Node<T>;
fn next(&mut self) -> Option<Node<T>> {
if self.nodes.len() == 0 {
None
} else {
let current: Option<Node<T>> = self.nodes.pop();
for it in current.iter() {
for n in it.left.iter() {
self.nodes.push(**n);
}
for n in it.right.iter() {
self.nodes.push(**n);
}
}
return current;
}
}
}
impl<T> Tree<T> {
pub fn new() -> Tree<T> {
Tree { root: None }
}
pub fn insert(&mut self, value: T) {
match self.root {
Some(ref mut n) => {
println!("Root is not empty, insert in node");
n.insert(value);
}
None => {
println!("Root is empty");
self.root = Some(Node::new(Some(value), None, None));
}
}
}
fn iter(&self) -> NodeIterator<T> {
NodeIterator { nodes: vec![self.root.unwrap()] }
}
}
fn main() {
println!("Hello, world!");
let mut tree: Tree<i32> = Tree::new();
tree.insert(42);
tree.insert(43);
for it in tree.iter() {
println!("{}", it);
}
}
Here is a minimal version of this issue:
struct Bob<T>(T);
impl<T> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}
fn main() {
let x = Bob(4);
println!("{}", x);
}
Let's take a look at our fmt function:
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
We can rewrite it as follows for better clarity:
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: ")?;
std::fmt::Display::fmt(&self.0, f)
}
Calling one of the formatting macros (write!, format!, println!, etc.) with double brackets in quotes, "{}", says to call the fmt function from the Display trait for that argument (self.0 in this case).
The problem is that we have some generic type T, so the compiler has no idea whether Display is implemented for it or not.
There are two ways to fix this.
First, we could add the constraint T: std::fmt::Display to our implementation of Display for Bob. This will let us use the struct with non-Display types, but Display will only be implemented when we use it with Display types.
That fix looks like this:
impl<T: std::fmt::Display> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}
Second, we could add that constraint to the struct definition, like this:
struct Bob<T: std::fmt::Display>(T);
This will mean that Bob is only generic with regards to types that are Display. It is more limiting and restricts the flexibility of Bob, but there may be cases where that is desired.
There are other traits similar to Display that can be called by putting different tokens in the brackets. The full list can be found in the documentation, but, for example, we could use the Debug trait with
write!(f, "Bob: {:?}", self.0)
only then we would need to be sure that T is std::fmt::Debug.
Related
After adding a RefCell to the inside struct, I don't know how to have a reference to only the Rc value.
In other words, I'm creating an Rc<RefCell<T>> but I only need the Rc<T> to be able to downgrade into a Weak.
use std::{
cell::RefCell,
fmt,
rc::{Rc, Weak},
};
#[derive(Debug)]
struct Field {
i: u8,
y: u8,
}
impl Field {
pub fn new() -> Self {
Self { i: 8, y: 6 }
}
}
#[derive(Debug)]
pub struct Parent {
field_1: Field,
child: RefCell<Option<Child>>,
}
impl Parent {
pub fn new() -> Rc<RefCell<Self>> {
let n = Rc::new(RefCell::new(Self {
field_1: Field::new(),
child: RefCell::new(None),
}));
*n.borrow_mut().child.borrow_mut() = Some(Child::new(&n));
n
}
pub fn modify(&mut self) {
self.field_1.i = 9;
}
pub fn to_string(&self) -> String {
format!(
"{:?} {}",
self.field_1,
self.child.borrow().as_ref().unwrap()
)
}
}
#[derive(Debug)]
pub struct Child {
parent: Weak<Parent>,
field_2: Field,
}
impl Child {
pub fn new(parent: &Rc<Parent>) -> Self {
Self {
parent: Rc::downgrade(parent),
field_2: Field::new(),
}
}
}
impl fmt::Display for Child {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.parent.upgrade().unwrap().field_1.i == 1 {
write!(f, "set: {:?}", self.field_2)
} else {
write!(f, "not set {:?}", self.field_2)
}
}
}
fn main() {
let mut parent = Parent::new();
parent.borrow_mut().modify();
println!("{}", parent.borrow().to_string());
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:32:62
|
32 | *n.borrow_mut().child.borrow_mut() = Some(Child::new(&n));
| ^^ expected struct `Parent`, found struct `std::cell::RefCell`
|
= note: expected reference `&std::rc::Rc<Parent>`
found reference `&std::rc::Rc<std::cell::RefCell<Parent>>`
I realize that the data structure itself might be the problem, but I currently can't think of a improvement.
I can understand borrowing/ownership concepts in Rust, but I have no idea how to work around this case:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
playground
The compiler has the error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I don't understand why I can't mutate in the match arm when I did a get (read value) before; the self.t.get is finished when the mutation via remove begins.
Is this due to scope of the result (Option<&u16>) returned by the get? It's true that the lifetime of the result has a scope inside the match expression, but this design-pattern is used very often (mutate in a match expression).
How do I work around the error?
The declaration of function HashMap::<K,V>::get() is, a bit simplified:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
This means that it returns an optional reference to the contained value, not the value itself. Since the returned reference points to a value inside the map, it actually borrows the map, that is, you cannot mutate the map while this reference exists. This restriction is there to protect you, what would happen if you remove this value while the reference is still alive?
So when you write:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
the captured r is of type &u16 and its lifetime is that of self.t, that is, it is borrowing it. Thus you cannot get a mutable reference to self, that is needed to call remove.
The simplest solution for your problem is the clone() solves every lifetime issue pattern. Since your values are of type u16, that is Copy, it is actually trivial:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Now r is actually of type u16 so it borrows nothing and you can mutate self at will.
If your key/value types weren't Copy you could try and clone them, if you are willing to pay for that. If not, there is still another option as your remove() function does not modify the HashMap but an unrelated HashSet. You can still mutate that set if you take care not to reborrow self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
You are trying to remove value from HashMap by using value you get, not key.
Only line 26 is changed Some(_) => self.remove(&v)
This will work:
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(_) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(1100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
play.rust
It seems that the following solution is good for primitive types like here u16. For other types, the ownership is moved.
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>,
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(&v) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
For other types, we must clone the value:
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Val {
t: HashMap<String, String>,
l: HashSet<String>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new(), l: HashSet::new() }
}
fn set(&mut self, k: String, v: String) {
self.l.insert(v.clone());
self.t.insert(k, v);
}
fn remove(&mut self, v: &String) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => {
let x = v.clone();
self.remove(&x)
}
}
}
fn do_task(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => self.l.insert(v.clone())
}
}
}
fn main() {
let mut v = Val::new();
v.set("AA".to_string(), "BB".to_string());
v.set("BB".to_string(), "CC".to_string());
println!("Start: {:#?}", v);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(&"AA".to_string()));
println!("Size after: {}", v.l.len());
println!("After: {:#?}", v);
println!("Task [Exist]: {}", v.do_task(&"BB".to_string()));
println!("Task [New]: {}", v.do_task(&"AA".to_string()));
println!("End: {:#?}", v);
}
But i'd like a solution that has no allocation
I'm learning Rust and I don't udestrand what is the problem of the following code
pub enum BagEntryState {
UNUSED, USED, REMOVED
}
impl PartialEq for BagEntryState {
fn eq(&self, other: &Self) -> bool {
self == other
}
}
pub struct BagEntry< T: std::cmp::PartialEq + fmt::Display> {
state : BagEntryState,
value: T,
}
impl<'a, T: std::cmp::PartialEq + fmt::Display> BagEntry<T> {
pub fn new(value: T) -> BagEntry< T> {
BagEntry {
value,
state: BagEntryState::UNUSED,
}
}
pub fn value(self)->T {
self.value
}
}
impl<'a, T: std::cmp::PartialEq + fmt::Display> PartialEq for BagEntry<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: std::cmp::PartialEq + fmt::Display> fmt::Display for BagEntry<T> {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
use core::fmt;
fn main() {
let my_bagentry = BagEntry::new(String::from("ciao"));
//println!("{}", my_bagentry.value());
let mut contVec : Vec<BagEntry<String>>=vec![];
contVec.push(my_bagentry);
println!("state ={}", contVec[0]);
println!("state ={}", contVec[0].value());
}
The code is not compiling becaus of the error:
54 | println!("state ={}", contVec[0].value());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `BagEntry<std::string::String>`, which does not implement the `Copy` trait
My guess is that the problem is that with value()
I'm exposing the struct inner value, but I cannot really understand where the problem is and how to solve it.
My aim is that BagEntry owns the value but I want safely expose it outside the struct
Basically what is happening:
pub fn value(self)->T {
self.value
}
Here -> T means that you are moving the struct field out of the struct. This is fine, but you cannot use your object anymore. You can verify this - you cannot call your println!("{}", my_bagentry.value()); twice in a row - after the first one the my_bagentry is invalidated.
If I understand correctly you want only to borrow the value out of the object. To do this you need change your method signature to borrowing one.
pub fn value(&self)-> &T {
&self.value
}
Now the call will only borrow on the object and the the resulting reference will have the lifetime of that borrow.
I'm trying to learn Rust (I come from Java) and I'm having some problems.
I'm building a simple program that is the base for a connection pool.
When I run it, I get the runtime error thread 'main' has overflowed its stack and I cannot understand why.
here is main.rs
use hello_rust::concurrent_bag;
use hello_rust::concurrent_bag::BagEntry;
fn main() {
let my_bagentry = BagEntry::new(String::from("ciao"));
//println!("{}", my_bagentry.value());
let mut contVec : Vec<BagEntry<String>>=vec![];
contVec.push(my_bagentry);
println!("state ={}", contVec[0]);
println!("state ={}", contVec[0].value());
let mut my_bag: concurrent_bag::ConcurrentBag<String> =concurrent_bag::ConcurrentBag::new();
my_bag.addEntry(String::from("ciao Entry"));
let result = my_bag.borrowEntry();
if result.is_some() {
println!("{}", result.unwrap().value());
}
}
and here is lib.rs
pub mod concurrent_bag {
use crate::concurrent_bag::BagEntryState::UNUSED;
pub enum BagEntryState {
UNUSED, USED, REMOVED
}
impl fmt::Display for BagEntryState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
BagEntryState::UNUSED => write!(f, "UNUSED"),
BagEntryState::USED => write!(f, "USED"),
BagEntryState::REMOVED => write!(f, "REMOVED"),
}
}
}
impl PartialEq for BagEntryState {
fn eq(&self, other: &Self) -> bool {
self == other
}
}
pub struct BagEntry< T: std::cmp::PartialEq + fmt::Display> {
state : BagEntryState,
value: T,
}
impl<'a, T: std::cmp::PartialEq + fmt::Display> BagEntry<T> {
pub fn new(value: T) -> BagEntry< T> {
BagEntry {
value,
state: UNUSED,
}
}
pub fn value(&self)->&T {
&self.value
}
pub fn state(&self)->&BagEntryState {
&self.state
}
}
impl<'a, T: std::cmp::PartialEq + fmt::Display> PartialEq for BagEntry<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: std::cmp::PartialEq + fmt::Display> fmt::Display for BagEntry<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
use std::sync::Arc;
use core::fmt;
pub struct ConcurrentBag<T: std::cmp::PartialEq + fmt::Display> {
entry_list:Vec<BagEntry<T>>,
}
impl<'a, T: std::cmp::PartialEq + fmt::Display> ConcurrentBag<T> {
pub fn new() -> ConcurrentBag<T> {
ConcurrentBag {
entry_list: vec![],
}
}
pub fn borrowEntry(&self) -> Option<BagEntry<T>> {
println!("borrow vc size {}", self.entry_list.len());
println!("value ={}", (self).entry_list[0].value());
println!("state ={}", (self).entry_list[0].state());
if (self).entry_list[0].state()==&UNUSED {
}
let result:Option<BagEntry<T>> =None;
result
}
pub fn addEntry(&mut self, value: T) {
let my_bagentry = BagEntry::new(value);
(*self).entry_list.push(my_bagentry);
println!("addEntry vc size {}", self.entry_list.len())
}
pub fn removeEntry(&mut self, value: T) {
let my_bagentry = BagEntry::new(value);
let index =(*self).entry_list.iter().position(|x| *x == my_bagentry).unwrap();
self.entry_list.remove(index);
}
}
}
The problematic line is
if (self).entry_list[0].state()==&UNUSED
and I can't undestrand why since the line
println!("state ={}", (self).entry_list[0].state());
seems to work well.
Another issue that puzzles me is that if I use &self in borrowEntry I should use *self for getting access to entry_list but the program compiles and runs without errors.
Doesn't this code repeat itself forever?
impl PartialEq for BagEntryState {
fn eq(&self, other: &Self) -> bool {
self == other
}
}
We implement PartialEq to make it possible to compare instances of a type with == and != operators. So, it doesn't make sense to use self == other in there.
You can just derive PartialEq.
#[derive(PartialEq)]
pub enum BagEntryState {
UNUSED,
USED,
REMOVED,
}
Or, if you want to implement it by hand, you can do something like this.
impl PartialEq for BagEntryState {
fn eq(&self, other: &BagEntryState) -> bool {
match (self, other) {
(&BagEntryState::UNUSED, &BagEntryState::UNUSED)
| (&BagEntryState::USED, &BagEntryState::USED)
| (&BagEntryState::REMOVED, &BagEntryState::REMOVED) => true,
_ => false,
}
}
}
I have an enum with two variants. Either it contains a reference to a Vec of Strings or it contains a Vec of references to Strings:
enum Foo<'a> {
Owned(&'a Vec<String>),
Refs(Vec<&'a String>),
}
I want to iterate over references to the Strings in this enum.
I tried to implement a method on Foo, but don't know how to make it return the right iterator:
impl<'a> Foo<'a> {
fn get_items(&self) -> Iter<'a, String> {
match self {
Foo::Owned(v) => v.into_iter(),
Foo::Refs(v) => /* what to put here? */,
}
}
}
fn main() {
let test: Vec<String> = vec!["a".to_owned(), "b".to_owned()];
let foo = Foo::Owned(&test);
for item in foo.get_items() {
// item should be of type &String here
println!("{:?}", item);
}
}
playground
What is an idiomatic method to achieve this abstraction over &Vec<T> and Vec<&T>? get_items may also return something different, as long as it implements the IntoIterator trait so that I can use it in the for loop.
You can't just use the std::slice::Iter type for this.
If you don't want to copy the strings or vector, you'll have to implement your own iterator, for example:
struct FooIter<'a, 'b> {
idx: usize,
foo: &'b Foo<'a>,
}
impl<'a, 'b> Iterator for FooIter<'a, 'b> {
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
self.idx += 1;
match self.foo {
Foo::Owned(v) => v.get(self.idx - 1),
Foo::Refs(v) => v.get(self.idx - 1).map(|s| *s),
}
}
}
impl<'a, 'b> Foo<'a> {
fn get_items(&'b self) -> FooIter<'a, 'b> {
FooIter { idx: 0, foo: self }
}
}
fn main() {
let test: Vec<String> = vec!["a".to_owned(), "b".to_owned()];
let foo = Foo::Owned(&test);
for item in foo.get_items() {
println!("{:?}", item);
}
let a = "a".to_string();
let b = "b".to_string();
let test: Vec<&String> = vec![&a, &b];
let foo = Foo::Refs(test);
for item in foo.get_items() {
println!("{:?}", item);
}
}
There is a handy crate, auto_enums, which can generate a type for you so a function can have multiple return types, as long as they implement the same trait. It's similar to the code in Denys Séguret's answer except it's all done for you by the auto_enum macro:
use auto_enums::auto_enum;
impl<'a> Foo<'a> {
#[auto_enum(Iterator)]
fn get_items(&self) -> impl Iterator<Item = &String> {
match self {
Foo::Owned(v) => v.iter(),
Foo::Refs(v) => v.iter().copied(),
}
}
}
Add the dependency by adding this in your Cargo.toml:
[dependencies]
auto_enums = "0.6.3"
If you don't want to implement your own iterator, you need dynamic dispatch for this, because you want to return different iterators depending on the enum variant.
We need a trait object (&dyn Trait, &mut dyn Trait or Box<dyn Trait>) to use dynamic dispatch:
impl<'a> Foo<'a> {
fn get_items(&'a self) -> Box<dyn Iterator<Item = &String> + 'a> {
match self {
Foo::Owned(v) => Box::new(v.into_iter()),
Foo::Refs(v) => Box::new(v.iter().copied()),
}
}
}
.copied() converts the Iterator<Item = &&String> into an Iterator<Item = &String>, so this doesn't actually copy anything :)
A few things you should know first:
You are most definitely going to have two different iterators, because they're different base types you're iterating over. Therefore I'm going to use a Box<dyn Iterator<Item = &'a _>>, but feel free to use an enum if this causes a quantifiable performance drop.
You need to introduce self's lifetime here, because what if we return an iterator whose lifetime is 'a, but 'a > 'self? Therefore we make a new lifetime (Which I'll call 'b.).
Now it's just a matter of wrangling with the reference layers:
Here's the implementation using the original types:
enum Foo<'a> {
Owned(&'a Vec<String>),
Refs(Vec<&'a String>)
}
impl<'a> Foo<'a> {
fn get_items<'b>(&'b self) -> Box<dyn Iterator<Item = &'a String> + 'b> {
match self {
Foo::Owned(v) => //v: &'a Vec<String>
Box::new(
v.iter() //Iterator<Item = &'a String> -- Good!
),
Foo::Refs(v) => //v: Vec<&'a String>
Box::new(
v.iter() //Iterator<Item = &'b &'a String> -- Bad!
.map(|x| *x) //Iterator<Item = &'a String> -- Good!
),
}
}
}
These types aren't really rust-like (Or more formally, idiomatic), so here's that version using slices and strs:
enum Foo<'a> {
Owned(&'a [String]),
Refs(Vec<&'a str>)
}
impl<'a> Foo<'a> {
fn get_items<'b>(&'b self) -> Box<dyn Iterator<Item = &'a str> + 'b> {
match self {
Foo::Owned(v) =>
Box::new(
v.into_iter()
.map(|x| &**x) //&'a String -> &'a str
),
Foo::Refs(v) =>
Box::new(
v.iter()
.map(|x| *x) //&'b &'a str -> &'a str
)/* what to put here? */,
}
}
}
Playground
Ideally you would want:
fn get_items(&self) -> impl Iterator<Item = &String> {
match self {
Foo::Owned(v) => v.into_iter(),
Foo::Refs(v) => v.iter().copied(),
}
}
The call to copied is here to convert an Iterator<Item = &&String> into the Iterator<Item = &String> we want. This doesn't work because the two match arms have different types:
error[E0308]: match arms have incompatible types
--> src/main.rs:12:30
|
10 | / match self {
11 | | Foo::Owned(v) => v.into_iter(),
| | ------------- this is found to be of type `std::slice::Iter<'_, std::string::String>`
12 | | Foo::Refs(v) => v.iter().copied(),
| | ^^^^^^^^^^^^^^^^^ expected struct `std::slice::Iter`, found struct `std::iter::Copied`
13 | | }
| |_________- `match` arms have incompatible types
|
= note: expected type `std::slice::Iter<'_, std::string::String>`
found type `std::iter::Copied<std::slice::Iter<'_, &std::string::String>>`
You can fix this error thanks to the itertools or either crates, which contain a handy adapter called Either (*) that allows you to choose dynamically between two iterators:
fn get_items(&self) -> impl Iterator<Item = &String> {
match self {
Foo::Owned(v) => Either::Left(v.into_iter()),
Foo::Refs(v) => Either::Right(v.iter().copied()),
}
}
playground