Skip to content
This repository has been archived by the owner on Nov 11, 2019. It is now read-only.
Permalink
Browse files
update for master in anticipation of 0.9
  • Loading branch information
steveklabnik committed Jan 5, 2014
1 parent 0fac145 commit ae27bcfc349450e3491e420c71f93357fb4c0f6d
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 302 deletions.
@@ -13,7 +13,7 @@ already use. Just do this:

If you don't use Homebrew, install it. Seriously.

(Note: If you're reading this close to release, Homebrew may not have 0.8 yet,
(Note: If you're reading this close to release, Homebrew may not have 0.9 yet,
you can use brew install --HEAD rust to get master, which will be close.)

Linux
@@ -22,9 +22,9 @@ Linux
I personally use Linux, and Rust works quite well on it. Rust does the Standard
Unix Thing.

$ curl -O http://static.rust-lang.org/dist/rust-0.8.tar.gz
$ tar -xzf rust-0.8.tar.gz
$ cd rust-0.8
$ curl -O http://static.rust-lang.org/dist/rust-0.9.tar.gz
$ tar -xzf rust-0.9.tar.gz
$ cd rust-0.9
$ ./configure
$ make
$ sudo make install
@@ -46,7 +46,7 @@ ask for help.
Future Proofing
---------------

The version this book is written for is 0.8.While the language itself is pretty
The version this book is written for is 0.9. While the language itself is pretty
stable, things like the standard library and some major subsystems are being
revised. I'll be tweaking it with every new release.

@@ -44,15 +44,3 @@ To run your program, do the Usual UNIX Thing:
$ ./hello

And you should see "Hello, world." print to the screen. Congrats!

There's an easier way to do this, too. Rust provides another tool, `rust`,
which wraps up a lot of functionality. We won't use `rustc` directly for the
rest of this book, because you almost always want to be working with the
higher-level tooling. Check it:

$ rust run hello.rs
Hello, world!

Yup, `rust run` combines the compile and run step. This will probably feel more
normal to you than keeping the two steps apart. It's only good for simple things,
though: soon enough we'll be using `rustpkg` instead. But that's for later...
@@ -26,9 +26,14 @@ fails. Let's give it a shot: Open up `testing.rs` and put this in it:
}
~~~

Then, use `rust run`'s buddy, `rust test`:
Then, use `rustc` with a special flag:

$ rust test testing.rs
$ rust --test testing.rs

This comment has been minimized.

Copy link
@Twisol

Twisol Jan 5, 2014

I don't know anything about Rust, but if you're swapping rust for rustc everywhere, shouldn't that be rustc --test, not rust --test?

This comment has been minimized.

Copy link
@steveklabnik

steveklabnik Jan 5, 2014

Author Owner

correct! Thank you.


This tells `rust` to compile your tests, and replaces the `main` function

This comment has been minimized.

Copy link
@Twisol

Twisol Jan 5, 2014

Line 29 refers to rustc, but you say rust here.

with a test runner. Try it out:

$ ./testing

You should get some output that looks like this:

@@ -231,29 +231,27 @@ out all the numbers from one to 100. It's easy!

~~~ {.rust}
fn main() {
do 100.times {
for num in range(0,100) {

This comment has been minimized.

Copy link
@pzol

pzol Jan 8, 2014

Is this really rust 0.8 -> 0.9 related or because for is more performant?

This comment has been minimized.

Copy link
@emberian

emberian Jan 8, 2014

Collaborator

it's really related. do was removed for non-proc() types.

println("num");
}
}
~~~

Step one: print **something** 100 times. If you run this with `rust run`
(not `rust test`!) you should see `num` printed 100 times. Note that
our tests didn't actually run. Not only are they not run, they're
actually not even in the executable:

$ rust test fizzbuzz.rs
Step one: print **something** 100 times. If you run this via
`rustc fizzbuzz.rs && ./fizzbuzz` you should see `num` printed
100 times. Note that our tests didn't actually run. Not only are they not run,
they're actually not even in the executable:

On Linux:

~~~
$ nm -C fizzbuzztest~ | grep test
$ nm -C fizzbuzz | grep test
~~~

On OS X:

~~~
$ nm fizzbuzztest~ | c++filt -p -i | grep test
$ nm fizzbuzz | c++filt -p -i | grep test
~~~

~~~
@@ -269,7 +267,7 @@ $ nm fizzbuzztest~ | c++filt -p -i | grep test
~~~

~~~
$ rust run fizzbuzz.rs
$ rustc fizzbuzz.rs
~~~

On Linux:
@@ -283,11 +281,10 @@ On OS X:
~~~
$ nm fizzbuzz~ | c++filt -p -i | grep test
~~~

$

Neat, huh? Rust is smart. By the way, you can see how `rust run` and `rust
test` work here: They compile and run a version of your file with a `~` at
the end.
Neat, huh? Rust is smart.

Anyway, `nm`: The `nm` program lists all the symbols in a binary executable or
library. The `-C` option is important on linux, it "de-mangles" the symbol names.
@@ -300,95 +297,31 @@ Anywho, where were we? Oh, iteration:

~~~ {.rust}
fn main() {
do 100.times {
println("num");
for num in range(0, 100) {
println(num)

This comment has been minimized.

Copy link
@alan-andrade

alan-andrade Jan 5, 2014

The ; was left out intentionally ?

This comment has been minimized.

Copy link
@steveklabnik

steveklabnik Jan 5, 2014

Author Owner

This is probably a typo. dammit.

}
}
~~~

Let's talk about `do`. `do` is actually syntax sugar. Here's the
equivalent without `do`:

~~~ {.rust}
fn main() {
100.times(|| {
println("num");
});
}
~~~

Note the extra parens and `||`. Typing out `});` really sucks, and having the
`({` is also awkward. Just like Ruby, Rust has special syntax when you're
passing a single closure to a method. Awesome. And it shouldn't surprise
Rubyists that you can pass a closure (read: block) to a method, and have it
loop. Let's print out the numbers now. First step: we need to get the number of
the current iteration. Rubyists will do a double take:

~~~ {.rust}
fn main() {
do 100.times |num| {
println("num");
};
}
~~~

Almost the same syntax, but with the pipes *outside* of the curlies.
But, if you try to run this, you'll get an error:

$ rust build fizzbuzz.rs
fizzbuzz.rs:45:12: 47:5 error: mismatched types: expected `&fn()` but found `&fn(<V0>)` (incorrect number of function parameters)
fizzbuzz.rs:45 do 100.times |num| {
fizzbuzz.rs:46 println("num");
fizzbuzz.rs:47 }
fizzbuzz.rs:45:12: 47:5 error: mismatched types: expected `&fn() -> bool` but found `&fn(<V0>) -> bool` (incorrect number of function parameters)
fizzbuzz.rs:45 do 100.times |num| {
fizzbuzz.rs:46 println("num");
fizzbuzz.rs:47 }
fizzbuzz.rs:45:12: 47:5 error: Unconstrained region variable #3
fizzbuzz.rs:45 do 100.times |num| {
fizzbuzz.rs:46 println("num");
fizzbuzz.rs:47 }
error: aborting due to 3 previous errors

The big one is this:

error: mismatched types: expected `&fn()` but found `&fn(<V0>)` (incorrect number of function parameters)
Note we've removed the quotes to print the number itself rather than the string
'num'. If we run this, we get another error message:

Expected `fn()` but got `fn(<V0>)`. It wants no parameters, but we gave
it one. Whoops! These kind of crazy compiler errors are a little hard to
read, especially since we don't get them at all in Ruby. The `<V0>` is
just rust trying to tell us that it doesn't quite know what type we
want: it's the first (index 0) inferred type it encountered in the
program. There is also `<VIx>`, for any `x`, which means it thought the
inferred type was an integer, and `<VFx>` for floats.
$ rustc fizzbuzz.rs && ./fizzbuzz
fizzbuzz.rs:46:16: 46:19 error: error: mismatched types: expected `&str`
but found `int` (expected &str but found int)

Anyway, we need a different function:

~~~ {.rust}
fn main() {
for num in range(1, 4) {
println(num);
}
}
~~~


Neat! If we run this, we get
another error message:

$ rust run fizzbuzz.rs
fizzbuzz.rs:46:16: 46:19 error: mismatched types: expected `&str` but found `<VI2>` (expected &str but found integral variable)
fizzbuzz.rs:46 println(num);
^~~
error: aborting due to previous error

Mismatched types: expected &str but found integral value. It wants a
string, but we gave it a number. Whoops! Now, there's two ways to fix
this. The first is to use the `to_str` function:
Mismatched types: expected &str but found int. It wants a string, but we gave
it a number. Whoops! Now, there's two ways to fix this. The first is to use the
`to_str` function:

~~~ {.rust}
fn main() {
for num in range(1, 4) {
for num in range(1, 100) {
println(num.to_str())
}
}
@@ -400,34 +333,45 @@ Awesome. Let's run it:
1
2
3
...
99

Bam! Whew. We had to fight with the compiler a bit, and the errors
weren't great, but that wasn't too bad. The other way to do it is to use
the `format!` macro, which will format-print our variables at
compile-time. Here it is:
the `format!` function. At least, it looks like a function to me. Here it
is:

~~~ {.rust}
fn main() {
for num in range(1, 4) {
println!("{:d}", num);
println(format!("{:d}", num));
}
}
~~~

`println!`, ie. `println(format!())` is similar to `str % arg`, or the
`format` and `sprintf` functions in `Kernel`: it takes a format string,
some arguments, and makes a string out of them.
A cool feature of Rust that sets it apart from C or C++, is that the
format strings are type-checked at compile time (the type annotation like
`:d` is otherwise optional).
No more broken format strings!
`format!` is similar to `str % arg`, or the `format` and `sprintf`
functions in `Kernel`: it takes a format string, some arguments, and
makes a string out of them. A cool feature of rust that sets it apart
from C or C++, which also have this, is that the format strings are
type-checked at compile time. No more broken format strings!

Because this combination is common, you can use `println!` as a combination of
`println` and `format!`:

~~~ {.rust}
fn main() {
for num in range(1, 100) {
println!("{:d}", num);
}
}
~~~

Anyway, now we have 1 to 3. We need 1 to 100.
Anyway, now we have 1 to 99. We need 1 to 100.

~~~ {.rust}
fn main() {
for num in range(1, 101) {
println(num.to_str());
println!("{:d}", num);
}
}
~~~
@@ -543,7 +487,7 @@ What's up with the tildes? They modify the declaration somehow. I added it
because running without it gives an error message that implies you need it:
give it a shot. Because our variables are typed, we have to convert the number
in the `else` case to a string. In Ruby we'd just let it be a `Fixnum` if it
was a number. Oh well.
was a number. Oh well. We'll talk more about them later.

Because the `if` returns a value, we could also do something like this:

1 comment on commit ae27bcf

@alan-andrade
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 and a 🍺 next time I see you because your work is awesome.

Please sign in to comment.