Coder Social home page Coder Social logo

too-many-lists's Introduction

Learn Rust by writing Entirely Too Many Linked Lists

Build Status

Read the pretty version at https://rust-unofficial.github.io/too-many-lists/.

Building

Building requires mdbook, which can be installed from crates.io:

cargo install mdbook

Assuming you've placed the install directory ~/.cargo/bin into your system PATH, then run from the root of your local copy:

mdbook build

If you'd prefer, this project can also be built with GitBook, although GitBook is not officially supported and compatibility is therefore uncertain and incidental.

too-many-lists's People

Contributors

bestouff avatar chirgjn avatar deebster avatar edunham avatar ericye16 avatar francozappa avatar gankra avatar gkoz avatar j89234682364 avatar jameslzhu avatar kontrafiktion avatar kylelaker avatar ldct avatar locks avatar louy2 avatar manishearth avatar martin-t avatar matthew-piziak avatar mbudde avatar mgeier avatar n8henrie avatar nertpinx avatar poorlydefinedbehaviour avatar reima avatar rwz avatar seeker14491 avatar snoyberg avatar tesuji avatar wheals avatar yanns avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

too-many-lists's Issues

3.5 (second-iter) dereference operator shows up in example with no explanation

The code at the top of 3.5 is missing lifetime specifiers. We start adding them in, only to go too far. After some discussion of lifetime elision, we "roll back to the no lifetimes state" but the code has changed. Now there are '*'s inside the closures we pass to the maps. There's no explanation, and the error message that follows makes it look like the code was run without the dereference operators in there (they are explained and added properly further down).

I think the dereferencing should be left out of the "Let's roll back to the no lifetimes state:" code block and the "We need to add lifetimes only in function and type signatures:" code block

Let's roll back to the no lifetimes state:

pub struct Iter<T> {
    next: Option<&Node<T>>,
}

impl<T> List<T> {
    pub fn iter(&self) -> Iter<T> {
-       Iter { next: self.head.map(|node| &*node) }
+       Iter { next: self.head.map(|node| &node) }
    }
}

impl<T> Iterator for Iter<T> {
    type Item = &T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
-           self.next = node.next.map(|node| &*node);
+           self.next = node.next.map(|node| &node);
            &node.elem
        })
    }
}

We need to add lifetimes only in function and type signatures:

// Iter is generic over *some* lifetime, it doesn't care
pub struct Iter<'a, T> {
    next: Option<&'a Node<T>>,
}

// No lifetime here, List doesn't have any associated lifetimes
impl<T> List<T> {
    // We declare a fresh lifetime here for the *exact* borrow that
    // creates the iter. Now &self needs to be valid as long as the
    // Iter is around.
    pub fn iter<'a>(&'a self) -> Iter<'a, T> {
-       Iter { next: self.head.map(|node| &*node) }
+       Iter { next: self.head.map(|node| &node) }
    }
}

// We *do* have a lifetime here, because Iter has one that we need to define
impl<'a, T> Iterator for Iter<'a, T> {
    // Need it here too, this is a type declaration
    type Item = &'a T;

    // None of this needs to change, handled by the above.
    // Self continues to be incredibly hype and amazing
    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
-           self.next = node.next.map(|node| &**node);
+           self.next = node.next.map(|node| &node);
            &node.elem
        })
    }
}

Rc::try_unwrap() no longer unstable

The code in this section calls for installing the unstable branch to get things to work.
This is no longer required as I'm able to compile this no problems in version 1.14.0.
Even the bit about adding .ok() after try_unwrap works without any sort of work-around

IntoIter

When doing https://rust-unofficial.github.io/too-many-lists/second-into-iter.html, clippy was politely mad at me.

defining a method called `into_iter` on this type; consider implementing the `std::iter::IntoIterator` trait or choosing a less ambiguous name

note: #[warn(clippy::should_implement_trait)] on by default
help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait

I'm completly new to rust but would that make sense ?

pub struct IntoIter<T>(List<T>);

-impl<T> List<T> {
+impl<T> std::iter::IntoIterator for List<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;

    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }
}

If not why ?

mismatched types

In chapter-2, implementing push the compiler gives the following error:

   Compiling lists v0.1.0 (/Users/gagan/dev/learnings/rust/lists)
error[E0308]: mismatched types
  --> src/first.rs:23:19
   |
23 |             next: self.head,
   |                   ^^^^^^^^^ expected struct `first::List`, found enum `first::Link`
   |
   = note: expected type `first::List`
              found type `first::Link`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `lists`.

To learn more, run the command again with --verbose.

Process finished with exit code 101

Code

pub struct List {
    head: Link,
}

enum Link {
    Empty,
    More(Box<Node>),
}

struct Node {
    elem: i32,
    next: List,
}

impl List {
    pub fn new() -> Self {
        List { head: Link::Empty }
    }

    pub fn push(&mut self, elem: i32) {
        let new_node = Node {
            elem,
            next: self.head, // here's the error
        };
    }
}

first::pop marked as causing compile errors actually compiles correctly

I am a novice in rust so not sure of the reasons. Maybe the language had an update? But the following code

pub fn pop(&mut self) -> Option<i32> {
    match mem::replace(&mut self.head, Link::Empty) {
        Link::Empty => None,
        Link::More(node) => {
            self.head = node.next;
            Some(node.elem)
        }
    }

is listed as causing compilation errors. In particular
error: use of moved value: node [E0382]
src/first.rs:36 Some(node.elem)

with the solution to use

Link::More(boxed_node) => {
            let node = *boxed_node;

However it compiled on my system. I am on Windows machine with the rustc version
rustc --version
rustc 1.31.1 (b6c32da9b 2018-12-18)

I have also tried on nightly channel and it compiled there as well.

Double linked list

First of all: thank a lot. I enjoyed reading this manual.

I cheated a bit and googled for "rust double linked list". There is seems to be solution to problem of who is owning who: stackoverflow.

Second link it to your website e.g. cglab.ca/~abeinges/blah/too-many-lists/book/

Additional Maintainers for this repo

Here's a thread for keeping track of those who'd like to help maintain this repo.

The duties of a maintainer are to:

  • check this repo's issues and PRs once in awhile
  • apply the relevant labels to any issues you notice are missing them
  • merge PRs that pass their tests and improve the book
  • Provide feedback on PRs which fail their tests or which you think would not improve the book
  • Follow the spirit of https://www.rust-lang.org/en-US/conduct.html in your role as a maintainer

If you haven't been invited yet but would like to help out, speak up in this thread!

[question] What is &**node (in Iter)?

I am not sure if it is OK to ask stupid questions here. I now feel like a student in a lecture that nods along the way and feels like he understand, until suddenly he doesn't.

I am not sure what does this line mean.

self.next = node.next.as_ref().map(|node| &**node);

Especially the end - &**node.

Why do I need to de-reference node twice and then reference again? * and & should be inverse functions, so instead of &**node we could write just *node, no?

I am obviously missing something, because I obviously cannot. I am not sure why not. :)

Mutability test for peek_mut on 3.3

Thanks for this awesome guide!

I tried to test the mutability of elem, accessed with peek_mut, like this

list.peek_mut().map(|&mut elem| {
    elem = 55;
});

assert_eq!(list.peek(), Some(&55));

and got error[E0384]: re-assignment of immutable variable 'elem' that still doesn't look obvious to me.

After awhile I came up with

list.peek_mut().map(|mut elem| {
    *elem = 55;
});

This (and some explanation) might be helpful to add.

Ch2 Drop Box<Node>

I'm getting two compile errors when implementing Drop for Box<Node>

  • error[E0425]: cannot find function deallocate in this scope
  • error[E0119]: conflicting implementations of trait std::ops::Drop for type std::boxed::Box<first::Node>
impl Drop for Box<Node> {
    fn drop(&mut self) {
      self.ptr.drop();
      deallocate(self.ptr);
    }
}
   Compiling lists v0.1.0 (file:///Users/williamrusnack/Documents/rust_practice/too_many_lists/lists)
error[E0425]: cannot find function `deallocate` in this scope
  --> src/first.rs:64:7
   |
64 |       deallocate(self.ptr);
   |       ^^^^^^^^^^ not found in this scope

error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<first::Node>`:
  --> src/first.rs:61:1
   |
61 | / impl Drop for Box<Node> {
62 | |     fn drop(&mut self) {
63 | |       self.ptr.drop();
64 | |       deallocate(self.ptr);
65 | |     }
66 | | }
   | |_^
   |
   = note: conflicting implementation in crate `alloc`:
           - impl<T> std::ops::Drop for std::boxed::Box<T>
             where T: ?Sized;

error: aborting due to 2 previous errors

error: Could not compile `lists`.

To learn more, run the command again with --verbose.

cargo 0.24.0 (45043115c 2017-12-05)
rustc 1.23.0 (766bd11c8 2018-01-01)

Surprise variable redifinition in 3.2

Section 3.2 has an example of switching the Option match to a map function. It redefines the variable named node from box to the unboxed value. I had to reread this line a couple times to be sure it was doing what I thought.

I think it's worth adding a comment describing this magic just happened, or change the code example to use different variable names. Something like

pub fn pop(&mut self) -> Option<i32> {
    self.head.take().map(|box_node| {
        let node = *box_node;
        self.head = node.next;
        node.elem
    })
}

2.5 Pop: Error 0382 "value used after move"

With rustc 1.27.0 (3eda71b00 2018-06-19), the final "idiomatic" example fails to compile. I found the following solution:

    pub fn pop(&mut self) -> Option<i32> {
        match mem::replace(&mut self.head, Link::Empty) {
            Link::Empty => None,
            Link::More(node) => {
                let elem = node.elem;
                self.head = node.next;
                Some(elem)
            }
        }
    }

However, as I am a Rust beginner, I have no idea how idiomatic this is.

it assumes cargo new makes a lib but it makes a bin

On the first page, the first instructions are
cargo new lists
cd lists

cargo new by default makes a bin, not a lib. The beginning of chapter 2 seems to indicate a lib was expected here.

I propose to change the above code in chapter 1 to include --lib

The list in "Ch2. A bad stack" is too complicated!

Could have been simpler?

use std::mem;

pub struct List {
    head: Box<Node>,
}

enum Node {
    Empty,
    Elem(i32, Box<Node>),
}

impl List {
    pub fn new() -> Self {
        List { head: Box::new(Node::Empty) }
    }

    pub fn push(&mut self, elem: i32) {
        let new_node =  Box::new(
                            Node::Elem(elem,
                               mem::replace(&mut self.head,
                                            Box::new(Node::Empty))));

        self.head = new_node;
    }

    pub fn pop(&mut self) -> Option<i32> {
        match *mem::replace(&mut self.head, Box::new(Node::Empty)) {
            Node::Empty => None,
            Node::Elem(i, next) => {
                self.head = next;
                Some(i)
            }
        }
    }
}

Inline Code Formatting

This is a silly pet peeve of mine, but I was going through and updating some error messages in the text and I was going to go on a rampage and throw all sorts of things into inline code format, but it looks like there's mostly an existing convention:

  • Type names that are words (Option, Link, Self) are usually not highlighted (but somewhat inconsistently). Unless it's something like Option<T> or Some(i32), which are always highlighted.
  • Keywords, variable names are highlighted.
  • Trait names (DerefMut, Copy, Iter) are inconsistent?

I would probably just throw all of the above into code highlighting, to avoid unbalanced sentences like

In the Empty case we need to return None. In the More case we need to return Some(i32)

I might be way overthinking this. Do other people have a preference?

lib.rs does not exist

Well that was fast. I got stuck on first slide

http://cglab.ca/~abeinges/blah/too-many-lists/book/first.html

We'll put our first list in first.rs. We need to tell Rust that first.rs is something that our lib uses. All that requires is that we put this at the top of lib.rs (which Cargo made for us):

There is no lib.rs.

There is src/ folder and src/main.rs, which is basically helo world.

Better build instructions

Currently the instructions offered are:

Building requires an instance of rustbook be set up on your machine. The only way to do this correctly is to build Rust from scratch with ./configure --enable-rpath and steal their copy of rustbook.

This isn't very helpful. Where do I find this project?

Can we not include the compiler in the repo? Or at least link to it?

Linked lists don't need to be bad for the cache

I'm just saying. Also, the wastage isn't always quite as bad as a full pointer.

use std::vec::*;

type Ix = u16;
const INVALID: Ix = 65535;

#[derive(Debug)]
struct Stack<A> {
    heads: Vec<Option<A>>,
    tails: Vec<Ix>,
    start: Ix,
    free: Ix,
    internal_len: usize
}

impl<A> Stack<A> {
    fn new() -> Self {
        Stack {
            heads: Vec::new(),
            tails: Vec::new(),
            start: INVALID,
            free: INVALID,
            internal_len: 0
        }
    }

    fn len(&self) -> usize {
        self.internal_len
    }

    fn push(&mut self, head: A) {
        let free = self.free;
        if free != INVALID {
            self.free = self.tails[free as usize];
            self.heads[free as usize] = Some(head);
            self.tails[free as usize] = self.start;
            self.start = free;
            self.internal_len += 1;
            return;
        }
        let n = self.heads.len();
        self.heads.push(Some(head));
        self.tails.push(self.start);
        self.start = n as Ix;
        self.internal_len += 1;
    }

    fn pop(&mut self) -> Option<A> {
        let start = self.start;
        if INVALID == start {
            return None;
        }
        self.start = self.tails[start as usize];

        self.tails[start as usize] = self.free;
        self.free = start;

        let res = self.heads[start as usize].take();
        self.internal_len -= 1;

        // If the stack length is a power of two gc.  This way if a
        // stack is 2^n and popped 2^n times it only gcs n times.
        // This means a total complexity of O(n^2) for 2^n pops and an
        // average complexity of O(1) for each pop.
        if 0 == self.internal_len || (self.internal_len & (self.internal_len - 1)) == 0 {
            self.gc();
        }

        return res;
    }

    fn gc(&mut self) {
        let mut end = INVALID;
        let mut new_heads = Vec::new();
        let mut new_tails = Vec::new();
        let mut start = self.start;
        if INVALID == start {
            self.heads = new_heads;
            self.tails = new_tails;
            self.free = INVALID;
            self.start = INVALID;
            return;
        }
        while start != INVALID {
            let new_end = new_heads.len() as Ix;
            if end != INVALID {
                new_tails[end as usize] = new_end;
            }
            new_heads.push(self.heads[start as usize].take());
            new_tails.push(INVALID);
            end = new_end;
            start = self.tails[start as usize];
        }
        self.heads = new_heads;
        self.tails = new_tails;
        self.free = INVALID;
        self.start = 0;
    }
}

fn main() {
    let mut s: Stack<u32> = Stack::new();
    s.push(2);
    s.pop();
    s.push(23);
    s.push(233);
    s.push(33);
    s.pop();
    loop {
        let popped = match s.pop() {
            None => break,
            Some(x) => x,
        };
        println!("{:?}", popped);
    }
    s.gc();
    println!("{:?}", s);
}

Dropping

I'm new to Rust, but I'm curious as to why we don't implement drop for the first two lists like this:

fn drop(&mut self) {
while let Some(_) = self.pop() {}
}

This seems like a very obvious implementation, and it seems more elegant than the given implementations. I ran a test which creates a list of a million elements and lets said list go out of scope, and everything went fine (the test resulted in stack overflow when I ran it before implementing drop).

Is there some reason I'm not seeing to prefer the given implementations?

let can shadow name in same block???

I was taken aback by this code in first.rs:

   Link::More(node) => {
            let node = *node;
            self.head = node.next;
            Some(node.elem)
        }

which appears to be equivalent to:

        Some(node_box) => {
            let node = *node_box;
            self.head = node.next;
            Some(node.elem)
        }

I tried to find something in the official Rust
documentation to justify shadowing a name
which is already in use in the block and didn't
find anything. Can you point to somewhere
which promises that this is stable? And maybe
something should be said to explain this to
newbies like me!

P.S. I'm absolutely loving this tutorial, it's
filling in key things I was missing!

Elaborate on lifetime in iter.next() in 3.6 IterMut

The signature of next establishes no constraint between the lifetime of the input and the output! Why do we care? It means we can call next over and over unconditionally!

I feel there's a gap of logic here. IIUC lifetime is meant to restrain the scope of output relative to input, and it is not intuitive how it would prevent next() to be called consecutively.

The specific example of

fn next<'b>(&'b mut self) -> Option<&'a T> { /* stuff */ }

would directly lead to the conclusion that Option<&'a T> lives as long as T lives, which is until that element is drop()ed or the whole list is dead. The key difference from Option<&'b T> would be when the element is drop()ed.

What happens when next() is called the second (and third) time?

first-push example doesn't compile

Hi! I've started working through this tutorial and run into a speed bump:

Everything went fine up until the end of http://cglab.ca/~abeinges/blah/too-many-lists/book/first-push.html, at which point:

   Compiling rustlinkedlists v0.1.0 (file:///Users/kr/src/github.com/kr/rustlinkedlists)
error[E0308]: mismatched types
  --> first.rs:29:26
   |
29 | 		self.head = Link::More(new_node);
   | 		                       ^^^^^^^^ expected box, found struct `first::Node`
   |
   = note: expected type `Box<first::Node>`
   = note:    found type `first::Node`

error: aborting due to previous error

error: Could not compile `rustlinkedlists`.

To learn more, run the command again with --verbose.

I took a guess and changed the expression to Link::More(Box::new(new_node)) and that made the error message go away, but I have no idea if that's the right thing to do.

Here's my entire first.rs reproduced exactly below, in case I've made a simple mistake copying it out of the tutorial:

use std::mem;

pub struct List {
	head: Link,
}

enum Link {
	Empty,
	More(Box<Node>),
}

struct Node {
	elem: i32,
	next: Link,
}

impl List {
	pub fn new() -> Self {
		List { head : Link::Empty }
	}
}

impl List {
	pub fn push(&mut self, elem: i32) {
		let new_node = Node {
			elem: elem,
			next: mem::replace(&mut self.head, Link::Empty),
		};
		self.head = Link::More(new_node);
	}
}

In case it matters, I'm using:

:; cargo --version
cargo 0.16.0-nightly (6e0c18c 2017-01-27)
:; rustc --version
rustc 1.15.1 (021bd294c 2017-02-08)

images ...

Would you be interested in some images (boxes and lines) that might make some concepts/problems clearer. E.g. it took me quite a while to grok:

pub fn pop(&mut self) -> Option<i32> {
    match mem::replace(&mut self.head, Link::Empty) {
        Link::Empty => None,
        Link::More(node) => {
            self.head = node.next;
            Some(node.elem)
        }
    }
}

So I created
pop_move2 2

If you are interested, I would create some more. For the one above, I have used draw.io, so it should be possible to edit them collaboratively, or do you know a better tool?

3.5. Iter: added 'a annotations result in syntax and other errors

Using Rust 1.34.0 and enabling "Edition 2018", the following code:

pub struct Iter<'a, T> {
    next: Option<&'a Node<T>>,
}

impl<'a, T> List<T> {
    pub fn iter(&'a self) -> Iter<'a, T> {
        Iter { next: self.head.map(|node| &'a node) }
    }
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    fn next(&'a mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.map(|node| &'a node);
            &'a node.elem
        })
    }
}

results in:

error: expected `:`, found `node`
  --> src/second.rs:54:47
   |
54 |         Iter { next: self.head.map(|node| &'a node) }
   |         ---- while parsing this struct        ^^^^ expected `:`

error: expected `:`, found `node`
  --> src/second.rs:62:50
   |
62 |             self.next = node.next.map(|node| &'a node);
   |                                                  ^^^^ expected `:`

error: expected `:`, found `node`
  --> src/second.rs:54:47
   |
54 |         Iter { next: self.head.map(|node| &'a node) }
   |         ---- while parsing this struct        ^^^^ expected `:`

error: expected `:`, found `node`
  --> src/second.rs:62:50
   |
62 |             self.next = node.next.map(|node| &'a node);
   |                                                  ^^^^ expected `:`

error[E0308]: method not compatible with trait
  --> src/second.rs:60:5
   |
60 |     fn next(&'a mut self) -> Option<Self::Item> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `fn(&mut second::Iter<'a, T>) -> std::option::Option<&T>`
              found type `fn(&'a mut second::Iter<'a, T>) -> std::option::Option<&T>`
note: the anonymous lifetime #1 defined on the method body at 60:5...
  --> src/second.rs:60:5
   |
60 | /     fn next(&'a mut self) -> Option<Self::Item> {
61 | |         self.next.map(|node| {
62 | |             self.next = node.next.map(|node| &'a node);
63 | |             &'a node.elem
64 | |         })
65 | |     }
   | |_____^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 58:6
  --> src/second.rs:58:6
   |
58 | impl<'a, T> Iterator for Iter<'a, T> {
   |      ^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `rusttest`.
warning: build failed, waiting for other jobs to finish...
error[E0308]: method not compatible with trait
  --> src/second.rs:60:5
   |
60 |     fn next(&'a mut self) -> Option<Self::Item> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `fn(&mut second::Iter<'a, T>) -> std::option::Option<&T>`
              found type `fn(&'a mut second::Iter<'a, T>) -> std::option::Option<&T>`
note: the anonymous lifetime #1 defined on the method body at 60:5...
  --> src/second.rs:60:5
   |
60 | /     fn next(&'a mut self) -> Option<Self::Item> {
61 | |         self.next.map(|node| {
62 | |             self.next = node.next.map(|node| &'a node);
63 | |             &'a node.elem
64 | |         })
65 | |     }
   | |_____^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 58:6
  --> src/second.rs:58:6
   |
58 | impl<'a, T> Iterator for Iter<'a, T> {
   |      ^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `rusttest`.

I don't understand the syntax errors. Commenting out the edition 2018 toggle doesn't help, either... What am I missing?

5.6 (fourth-iteration) missing borrow in sample code

In this code sample, the error message makes it apparent that the closure inside the map is missing a .borrow() call.

Woof. Let's give it a try...

fn next(&mut self) -> Option<Self::Item> {
    self.0.take().map(|node_ref| {
        let (next, elem) = Ref::map_split(node_ref, |node| {
            (&node.next, &node.elem)
        });

-       self.0 = next.as_ref().map(|head| head);
+       self.0 = next.as_ref().map(|head| head.borrow());


        elem
    })
}
cargo build
   Compiling lists v0.1.0 (/Users/ABeingessner/dev/temp/lists)
error[E0521]: borrowed data escapes outside of closure
   --> src/fourth.rs:159:13
    |
153 |     fn next(&mut self) -> Option<Self::Item> {
    |             --------- `self` is declared here, outside of the closure body
...
159 |             self.0 = next.as_ref().map(|head| head.borrow());
    |             ^^^^^^   ---- borrow is only valid in the closure body
    |             |
    |             reference to `next` escapes the closure body here

Inconsistent Chaos Due to Nonlinear Workflows

I occasionally back-ported some changes to previous chapters, leading to inconsistent or psychic compiler output in some places. In particular tests will appear and disappear in some areas where they shouldn't and should be. Number of tests run is also inconsistent in some places.

Also some final code pages may no longer have the actual final code. Man, it would be great if someone fixed that!

Suuuure would.

Basic Data Layout unclear on enum vs struct heap allocation issue

My understanding of the respective layouts for the enum vs. struct approaches described in the 'Basic Data Layout' chapter, are, for a two-element list:

Elem(i32, Box<Elem(i32, Box<Empty>)>), two heap allocations.
vs.
More(Box<{i32, More(Box<{i32, Empty}>)}>), also two heap allocations.

Why is this incorrect? Or if it is correct, why are the allocations required for the struct case better than those required for the enum case?

Chapter 3.2 Use of moved value error in Rust 1.33

I've followed through this excellent tutorial to Chapter 3.2 and after converting my functions to support generics, I encounter the following compiler error in the pop function:

error[E0382]: use of moved value: `node`
  --> src\second.rs:29:13
   |
28 |             self.head = node.next;
   |                         --------- value moved here
29 |             node.elem
   |             ^^^^^^^^^ value used here after move
   |
   = note: move occurs because `node.next` has type `std::option::Option<std::boxed::Box<second::Node<T>>>`, which does not implement the `Copy` trait

My pop function is defined as per the tutorial:

pub fn pop(&mut self) -> Option<T> {
    self.head.take().map(|node| {
        self.head = node.next;
        node.elem
    })
}

I had previously worked around this error by introducing a temporary variable as below, but this technique doesn't work with the generic definition:

pub fn pop(&mut self) -> Option<i32> {
    self.head.take().map(|node| {
        let result = node.elem;
        self.head = node.next;
        result
    })
}

My rust version is rustc 1.33.0 (2aa4c46cf 2019-02-28). Do I need a newer version?

Broken link?

This may be just me, but this link appears to be broken. Is there another place where this is hosted? It's a great resource that I would like to point others to.

Possible inconsistency in first.rs

Hi, thank you for this project, I am trying to learn rust using this book. Since I am a rust noob I might be wrong here (if I am then sorry for bothering you πŸ˜… : ) but this was confusing me so I thought I should raise an issue to get some clarification.

In first.rs the push function definition changes from

let new_node = Node {
            elem: elem,
            next: self.head,
        };

to

let new_node = Box::new(Node {
        elem: elem,
        next: self.head,
    });

without any explanation why Node{} was changed to Box::new(Node{})

Explanation of "uniformity"

It would be nice to have some explicit explanation of what "(non)-uniformity" is, in the context you use it (section 2.1).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.