rust-unofficial / too-many-lists Goto Github PK
View Code? Open in Web Editor NEWLearn Rust by writing Entirely Too Many linked lists
Home Page: https://rust-unofficial.github.io/too-many-lists/
License: MIT License
Learn Rust by writing Entirely Too Many linked lists
Home Page: https://rust-unofficial.github.io/too-many-lists/
License: MIT License
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);
}
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
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.
Here's a thread for keeping track of those who'd like to help maintain this repo.
The duties of a maintainer are to:
If you haven't been invited yet but would like to help out, speak up in this thread!
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?
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:
Option<T>
or Some(i32)
, which are always highlighted.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?
The following link in the introduction (README.md) is broken (404):
[slices]: https://doc.rust-lang.org/book/slice-patterns.html
Hi, following your model, I expanded on the immutable, persistent linked list and added some features. I'm wondering whether you might find some of them useful to include, or have critiques on my attempt to learn low-level Rust: https://github.com/FranklinChen/immutable-list-rust
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/
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?
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.
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)
}
}
}
}
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
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
};
}
}
Thankyou for this amazing learning resource!
The text kept me entertained and I learned so much about rust ^^
Now lets move to the serious matter: The Error Report
Chapter 3.4 spelling error: "coallesces" should be "coalesces" (https://dict.leo.org/englisch-deutsch/coalesce)
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.
From https://www.reddit.com/r/rust/comments/3geb5q/learning_rust_with_entirely_too_many_linked_lists/ctxgwmz, maybe explain &**node
to make it more obvious what is being dereferenced. Coming from C, this was a little confusing.
http://cglab.ca/~abeinges/blah/too-many-lists/book/ is giving an error 403 and it's not the first time I've seen it down in the last year or so.
Perhaps a pre-rendered version could be offered via GitHub Pages to improve availability?
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.
I kinda just do whatever I feel like at that precise moment in time. It's 50/50 throughout the text.
I'm getting two compile errors when implementing Drop
for Box<Node>
deallocate
in this scopestd::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)
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?
http://cglab.ca/~abeinges/blah/too-many-lists/book/third-basics.html
pub fn tail(&self) -> List<T> {
List { head: self.head.map(|node| node.next.clone()) }
}
should be self.head.as_ref(), which matches up with the error and later code samples
The signature of
next
establishes no constraint between the lifetime of the input and the output! Why do we care? It means we can callnext
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?
In file https://github.com/Gankro/too-many-lists/blob/master/text/third-basics.md
line 66:
List { head: self.head.map(|node| node.next.clone()) }
line 78-79
src/third.rs:28 List { head: self.head.as_ref().map(|node| node.next.clone()) }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
line 90:
List { head: self.head.as_ref().and_then(|node| node.next.clone()) }
Seems like we passed from head.map
to head.as_ref().map
with no explanation
see:
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?
It would be nice to have some explicit explanation of what "(non)-uniformity" is, in the context you use it (section 2.1).
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
})
}
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?
In http://cglab.ca/~abeinges/blah/too-many-lists/book/third-basics.html,
pub fn tail(&self) -> List<T> {
List { head: self.head.map(|node| node.next.clone()) }
}
should read
pub fn tail(&self) -> List<T> {
List { head: self.head.as_ref().map(|node| node.next.clone()) }
}
http://cglab.ca/~abeinges/blah/too-many-lists contains an outdated version (e.g. the code still uses nightly for #[feature]
). Please update.
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.
I found the following line a bit obscure
* Rust understands that it's ok to shard a mutable reference into the subfields
of the pointed-to struct, because there's no way to "go back up", and they're
definitely disjoint.
From https://github.com/Gankro/too-many-lists/blob/master/text/second-iter-mut.md at line 199
Maybe expand a little on the explanation ? Also I found no way to go backup
too ambiguous/unclear on this context.
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)
}
}
}
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?
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)
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{})
This commit "fixed" it by simply removing all references to unstable. In my opinion, you might as well keep the old version of the text then since the new one doesn't make much sense.
http://cglab.ca/~abeinges/blah/too-many-lists/book/first-pop.html has one bit rendered as
Unconditional panics are an example of a [diverging function][diverging].
This looks like a missing link. I donβt know what link was intended.
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!
hi I think there is an error in file too-many-lists/master/text/third-basics.md line 60
maybe the word removes should be replaced with returns in order to make more sense.
tail
is the logical inverse of this operation. It takes a list and removes the
whole list with the first element removed.
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
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 ?
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
})
}
}
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. :)
ie https://travis-ci.org/rust-unofficial/too-many-lists/builds/176181181
basically just find a working version and specify it here
#!feature[rc_unique]
is no longer necessary, since try_unwrap()
has been stabilized.
This effects the text in
and the source in
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
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.
Even better if we can make it work with #37
Indy has gone without anybody noticing that he's gone!
On the website the link to http://cglab.ca/%7Eabeinges/blah/too-many-lists/indy.gif in secion 2.4: Push is broken.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.