How to properly solve lifetime inferences in struct? - rust

The Rust playground code is here.
I have a struct of Token which has lifetime 'tok, and a scanner has lifetime 'lexer. I'm using both of them in another struct Parser, then I had a problem:
pub struct Token<'tok> {
pub value: Cow<'tok, str>,
pub line: usize,
}
pub struct Scanner {
pub source: Vec<char>,
pub current: usize,
pub line: usize,
}
pub struct Parser<'lexer> {
pub curr: &'lexer Token<'lexer>,
pub prev: &'lexer Token<'lexer>,
scanner: &'lexer mut Scanner,
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&mut self) {
self.prev = self.curr;
self.curr = &self.scanner.next(); // cannot inference lifetime
}
}
I think the problem is Token has lifetime 'tok, and the borrow checker doesn't know the relation between 'tok and 'lexer so it can't inference proper lifetime.
However, I can avoid the problem by modifying it into the updated code:
pub struct Parser<'lexer> {
pub curr: Token<'lexer>,
pub prev: Token<'lexer>,
scanner: &'lexer mut Scanner,
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&mut self) {
let prev = std::mem::replace(&mut self.curr, self.scanner.next());
self.prev = prev;
}
}
And with Token produced by next() is static:
impl Scanner {
pub fn next(&mut self) -> Token<'static> {
Token {
value: Cow::from(""),
line: 0,
}
}
}
It does compile but I think it's not ideal because all tokens are cloned from scanner into parser(they are not references anymore) and living until end of Parser's life. So memory usage is doubled. Is there a more proper way to deal with this?

Actualy your code structure is not ideal to deal with the borrow checker here why:
Token struct should be owned, the struct itself do not require any allocations (as the token is owned some indrection are required to allow prev <-> next switching)
None of the Parser or Lexer should own the base data so it will be easy to bound proper lifetime
In our case Vec<Char> is not a friendly type to work with (we do not need to own the data and this will be harder to make the comipler understand lifetimes), instead we're going to use an &'str but you could reproduce the exact behaviours with an &[char])
Here is an example that compile just fine
pub struct Token<'source> {
pub value: Cow<'source, str>,
pub line: usize,
}
pub struct Scanner<'source> {
pub source: &'source str,
pub current: usize,
pub line: usize,
}
pub struct Parser<'source> {
pub curr: Option<Token<'source>>,
pub prev: Option<Token<'source>>,
scanner: Scanner<'source>,
}
impl <'source>Scanner<'source> {
pub fn next(&'source /* DONT Forget to bound 'source to `self` */ self) -> Token<'source> {
Token {
value: Cow::from(self.source), /* `self.source` is bound to `'source` so the compiler understand that the token lifetime is the same than the source's one */
line: 0,
}
}
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&'lexer mut self) {
self.prev = self.curr.take();
self.curr = Some(self.scanner.next());
}
}

Related

How to set the lifetime on these structures?

I am trying to make an Iterator which filters out certain moves from a movelist. In order not to take ownership of the returned moves, they get referenced. However, when doing that, the missing lifetime specifier compiler error appears. As I have a chain of structs, I thought the first step to solve the problem was to start putting lifetimes on MoveFilter and then onto it's type Item in IntoIterator. However there it complains the usage of an undeclared lifetime.
Code:
pub struct GameMove {
pub from: usize,
pub to: usize,
pub move_type: GameMoveType,
pub piece_type: PieceType,
}
#[derive(PartialEq, Clone, Debug)]
pub enum GameMoveType {
Quiet,
Capture(PieceType),
}
#[derive(PartialEq, Clone, Debug)]
pub enum PieceType {
King,
Pawn
}
pub fn match_move_type(move_type: &GameMoveType) -> usize {
match move_type {
GameMoveType::Quiet => 0,
GameMoveType::Capture(_) => 1,
}
}
pub struct MoveFilter<'a> {
legal_moves: Vec<GameMove>,
move_type: GameMoveType,
}
impl IntoIterator for MoveFilter {
type Item = &'a GameMove;
type IntoIter = MoveFilterIterator;
fn into_iter(self) -> Self::IntoIter {
MoveFilterIterator {
legal_moves: self.legal_moves,
move_type: match_move_type(&self.move_type),
index: 0,
}
}
}
pub struct MoveFilterIterator {
legal_moves: Vec<GameMove>,
move_type: usize,
index: usize,
}
impl Iterator for MoveFilterIterator {
type Item = &GameMove;
fn next(&mut self) -> Option<&GameMove> {
while self.index < self.legal_moves.len() {
if match_move_type(&self.legal_moves[self.index].move_type) == self.move_type {
Some(&self.legal_moves[self.index])
} else {
self.index += 1;
}
}
None
}
}
There is a discrepancy between your
method fn into_iter(self: MoveFilter) that takes ownership of MoveFilter
and
the method fn next(&mut self) -> Option<&GameMove> that only wants to hand out immutable references to GameMoves. Who is supposed to own the referenced GameMoves after your into_iter takes ownership of the MoveFilter and completely consumes it?
One way to fix it would be to implement IntoIterator for &'a MoveFilter, that does not take ownership of MoveFilter, and thus does not have to worry that all GameMoves are discarded while there are any references &'a GameMove floating around:
pub struct GameMove {
pub from: usize,
pub to: usize,
pub move_type: GameMoveType,
pub piece_type: PieceType,
}
#[derive(PartialEq, Clone, Debug)]
pub enum GameMoveType {
Quiet,
Capture(PieceType),
}
#[derive(PartialEq, Clone, Debug)]
pub enum PieceType {
King,
Pawn
}
pub fn match_move_type(move_type: &GameMoveType) -> usize {
match move_type {
GameMoveType::Quiet => 0,
GameMoveType::Capture(_) => 1,
}
}
pub struct MoveFilter {
legal_moves: Vec<GameMove>,
move_type: GameMoveType,
}
impl<'t> IntoIterator for &'t MoveFilter {
type Item = &'t GameMove;
type IntoIter = MoveFilterIterator<'t>;
fn into_iter(self) -> Self::IntoIter {
MoveFilterIterator {
legal_moves: &self.legal_moves[..],
move_type: match_move_type(&self.move_type),
index: 0,
}
}
}
pub struct MoveFilterIterator<'a> {
legal_moves: &'a [GameMove],
move_type: usize,
index: usize,
}
impl<'a> Iterator for MoveFilterIterator<'a> {
type Item = &'a GameMove;
fn next(&mut self) -> Option<&'a GameMove> {
while self.index < self.legal_moves.len() {
if match_move_type(&self.legal_moves[self.index].move_type) == self.move_type {
return Some(&self.legal_moves[self.index])
} else {
self.index += 1;
}
}
None
}
}
Another possible solution would be to leave your IntoIterator for MoveFilter as-is, but then change Item = &GameMove to Item = GameMove. This would give you a destructive iterator that moves the MoveFilter and that can be used only once, but I assume that's not what you wanted when you began with type Item = &GameMove. Implementing it seems a bit more awkward, because it's not entirely trivial to remove single elements from a vector, and I didn't quite understand what that while-loop was doing there.

Creation of a hashmap with struct in Rust

I am trying to set up a hashmap of objects / structs in rust... But I don't understand this concrete problem (a lifetime error).
#[derive(Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node>,
}
impl<'a> Application<'a> {
fn join(&self, node: &Node) {
self.hash_map.insert(node.identifier, node);
}
}
The error is a missing lifetime specifier in the hash_map: HashMap<&'a str, Node> that I tried to solve changing Node to Node<'a> but It throws a "mismatched type" error when I try to insert...
I don't exactly why I have this problem missing the lifetime and I don't find solutions..
UPDATE:
#[derive(Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&self, node: &Node) {
self.hash_map.insert(node.identifier, *node);
}
}
And the output is:
"explicit lifetime required in the type of `node`"
UPDATE2:
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&mut self, node: &'a Node<'a>) {
self.hash_map.insert(node.identifier, *node);
}
}
And the output is:
self.hash_map.insert(node.identifier, *node); cannot move out of borrowed content
COMPLETE SOLUTION
#[derive(Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&mut self, node: Node<'a>) {
self.hash_map.insert(node.identifier, node);
}
}
This simplified example seems to work:
use std::collections::HashMap;
#[derive(Clone)] // we'll be cloning it later on
struct Node<'a> {
data: &'a i32
}
struct Test<'a> {
hash_map: HashMap<&'a str, Node<'a>> // the hash map owns the struct
}
impl<'a> Test<'a> {
fn new() -> Test<'a> {
Test {hash_map: HashMap::new()}
}
fn join(
&mut self, // must be mutable
node: Node<'a>) { // do not pass a reference
self.hash_map.insert("test", node); // inserting moves `node`
}
}
fn main() {
let stuff = Node {data: &12};
let mut test = Test::new();
test.join(stuff.clone()); // if we don't clone, `stuff` will get moved
println!("{}", *test.hash_map["test"].data); // outputs "12"
}
Since std::collections::HashMap::insert attempts to move its second argument, one can't dereference a pointer to something and pass that to this method because otherwise the pointer will become uninitialized, which isn't permitted. A way so solve this is to pass a moved value and not a pointer to join.
For poor idiots like myself, who are trying to find out how to put hashmaps in a struct, no need to spend many hours "playing" with lifetimes(the 'a in the above example). They are not required in the slightest, just use String instead of &str in your structure.
struct ComputerConfig {
hostname: String,
// displays: Vec<DispConfig>,
}
struct MyConfig {
pub config_version: u8,
computers: HashMap<String, ComputerConfig>, // the hash map owns the struct
}
impl MyConfig {
fn new() -> MyConfig {
MyConfig {
computers: HashMap::new(),
config_version: 1,
}
}
/// Join is used to add a new ComputerConfig into the hashmap
fn join(
&mut self, // must be mutable
key: &str,
node: ComputerConfig,
) {
// do not pass a reference
self.computers.insert(key.to_string(), node); // inserting moves `node`
}
}
fn main() {
let mut cfg = MyConfig::new()
cfg.join("test", stuff);
println!("{:?}", &cfg); // outputs "12"
}

Two similar code snippets but only one triggers a lifetime error

#![feature(rustc_private)]
extern crate rustc;
use rustc::hir::intravisit as hir_visit;
use rustc::hir;
use std::marker::PhantomData;
// ----------------------------------------------------------------------------
// Why does this compile?
// ----------------------------------------------------------------------------
pub struct Map<'a> {
pub _m: PhantomData<&'a ()>,
}
pub struct SomeVisitor<'a, 'tcx: 'a> {
pub map: &'a Map<'tcx>,
}
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
None,
OnlyBodies(&'this Map<'tcx>),
All(&'this Map<'tcx>),
}
pub trait Visitor<'v>: Sized {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
}
impl<'v, 'tcx> Visitor<'v> for SomeVisitor<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::All(self.map)
}
}
// ----------------------------------------------------------------------------
// Why does this *not* compile?
// ----------------------------------------------------------------------------
pub struct SomeVisitor2<'a, 'tcx: 'a> {
pub map: &'a hir::map::Map<'tcx>,
}
impl<'v, 'tcx> hir_visit::Visitor<'v> for SomeVisitor2<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
hir_visit::NestedVisitorMap::All(self.map)
}
}
fn main() {}
playground
NestedVisitorMap and Visitor
I recently ran into a lifetime issue and I decided to recreate it without any dependencies. The odd thing is that I can not recreate the lifetime error. To me both implementations look the same from the outside, but only one compiles successfully. Why is that?
rustc 1.21.0-nightly (e26688824 2017-08-27)
Update:
The problem seems to be the RefCell inside Map.
#[derive(Clone)]
pub struct Map<'hir> {
inlined_bodies: RefCell<rustc::util::nodemap::DefIdMap<&'hir hir::Body>>,
}
If there is a RefCell with a inner lifetime, it will trigger an error.
playground
Update2:
It turns out that I just mixed up lifetime subtyping. playground
I still don't know why only RefCell causes the error.

Is using to_owned() the idiomatic way to update a struct in place?

I was playing around with updating a Rust struct in place using chained methods. I found a way to do this, but I was not sure if my code below was idiomatic Rust versus just a workaround.
In particular, I used .to_owned() at the end of the chained method to return the borrowed struct. The code compiles and works just fine. Here is the minimal example.
//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
run: i32,
year: i32,
}
impl ModelDataCapture {
pub fn new() -> Self {
ModelDataCapture::default()
}
pub fn set_run(&mut self, run: i32) -> &mut ModelDataCapture {
self.run = run;
self
}
pub fn set_year(&mut self, year: i32) -> &mut ModelDataCapture {
self.year = year;
self
}
}
//main.rs
let data_capture = ModelDataCapture::new()
.set_run(0)
.set_year(1)
.to_owned(); // <<< QUESTION
println!("here is the data capture {:?}", data_capture);
Is this the proper way to write this in-place modification of the struct? If I do not include the .to_owned() method at the end of the chain, the compile fails with a message that the temporary variable does not live long enough.
Your code "works" but doesn't make sense to me. It:
Creates a value
Mutates the value
Clones the value
Throws away the original value
See the inefficiency? In addition, all the "in-place mutation" is completely discarded, so there's no benefit to it.
I'd generally introduce a binding to mutate:
let mut data_capture = ModelDataCapture::new();
data_capture.set_run(0).set_year(1);
Or go all the way and create a builder that has some equivalent of finish or build
#[derive(Debug)]
struct ModelDataCapture {
run: i32,
year: i32,
}
#[derive(Debug, Default)]
struct ModelDataCaptureBuilder {
run: i32,
year: i32,
}
impl ModelDataCaptureBuilder {
fn set_run(self, run: i32) -> Self {
ModelDataCaptureBuilder { run, ..self }
}
fn set_year(self, year: i32) -> Self {
ModelDataCaptureBuilder { year, ..self }
}
fn build(self) -> ModelDataCapture {
let ModelDataCaptureBuilder { run, year } = self;
ModelDataCapture { run, year }
}
}
fn main() {
let data_capture = ModelDataCaptureBuilder::default().set_run(0).set_year(1).build();
println!("here is the data capture {:?}", data_capture);
}
See Do Rust builder patterns have to use redundant struct code? for more examples of builders that mirror the built items.
You could take self by-value in the first example, but that's annoying in most cases, as you always have to remember to bind the result.
You could change the function to take ownership over self and return self.
Because each "setter" method returns the ownership of self, this code should work out nicely.
For more information, please checkout the rust book
//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
run: i32,
year: i32,
}
impl ModelDataCapture {
pub fn new() -> Self {
ModelDataCapture::default()
}
pub fn set_run(mut self, run: i32) -> ModelDataCapture {
self.run = run;
self
}
pub fn set_year(mut self, year: i32) -> ModelDataCapture {
self.year = year;
self
}
}
fn main() {
//main.rs
let data_capture = ModelDataCapture::new().set_run(0).set_year(1);
println!("here is the data capture {:?}", data_capture);
}

What kind of lifetime parameter do I have to use here when declaring a struct field object type

This is what my code looks like. I'm trying to use a impled struct within my ShapeRenderer struct and use its methods.
shapes.rs:
use super::core::*;
pub struct ShapeRenderer<'a> {
core_renderer: &'a mut CanvasRenderer,
}
core.rs
pub struct Canvas {
pub width: usize,
pub height: usize,
pub array: Vec<char>,
}
pub struct Point {
pub x: usize,
pub y: usize,
}
pub struct CanvasRenderer<'a> {
canvas: &'a mut Canvas,
}
impl<'a> CanvasRenderer<'a> {
pub fn new(canvas: &'a mut Canvas) -> CanvasRenderer {
CanvasRenderer { canvas: canvas }
}
}
Error
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/shapes.rs:5:28
|
5 | core_renderer: &'a mut CanvasRenderer
| ^^^^^^^^^^^^^^ expected 1 lifetime parameter
I marked it with a lifetime parameter - why does it want another one? tried the object type with <'a> and appended it <'a> - neither of those attempts solved the problem.
CanvasRenderer is parameterized over a lifetime, so you need to state what that lifetime is:
pub struct ShapeRenderer<'a> {
core_renderer: &'a mut CanvasRenderer<'a>,
// ^^^^
}
However, this structure doesn't seem to have much purpose, it only adds indirection. Why have a reference to a thing that only has a reference? Skip the middleman:
pub struct ShapeRenderer<'a> {
core_renderer: CanvasRenderer<'a>,
}

Resources