Skip to content

Commit 6f8e6c9

Browse files
2nd edition - support rust 2018
1 parent 1d7fc43 commit 6f8e6c9

40 files changed

+747
-233
lines changed

.vscode/extensions.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"recommendations": [
3+
"bungcip.better-toml",
4+
"esbenp.prettier-vscode",
5+
"rust-lang.rust"
6+
]
7+
}

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"prettier.arrowParens": "always",
4+
"prettier.singleQuote": true
5+
}

README.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
> An introduction to the Rust programming language for Node developers.
44
5-
Hi there, [I'm a JavaScript developer](https://github.com/donaldpipowitch) who wants to learn Rust and as a part of this process I'll write here about my learnings. So what is Rust actually and **why should you learn it**? Rust is a systems programming language like C or C++, but with influences from functional programming languages and even scripting languages like JavaScript. It _feels_ very modern - which is no surprise, because it is a relatively young language. [It went 1.0 in 2015!](http://blog.rust-lang.org/2015/05/15/Rust-1.0.html) That doesn't only mean it is _fun to write_, because it has less clutter to carry around, it is also _fun to use_, because it has a modern toolchain with a great package manager. Rust's most unique feature is probably the compile-time safety check: it catches errors like segfaults without introducing a garbage collector. Or to phrase it differently: maximum safety with maximum performance.
5+
> 💡 **2nd edition.** I initially wrote this tutorial in the summer of 2016. Rust 1.0 was roughly a year old back than. This tutorial stayed quite popular over time even though I haven't added new chapters. As years passed by the Rust (and Node) ecosystem evolved further and this tutorial wasn't up-to-date with all changes. With the recent release of [_"Rust 2018"_](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html) (which I'll explain later in more depth) I took the opportunity to update this tutorial as well. Enjoy the read! 🎉
66
7-
Probably even more important than its features is the ecosystem and the community behind the language. Rust really shines here - especially for people who love the web. It is **backed by Mozilla** and the **biggest real world project** written in Rust is probably [servo](https://github.com/servo/servo), a modern browser engine. servo is very modular - e.g. you can require its [HTML parser as a standalone module](https://github.com/servo/html5ever). Can you do that with any other browser engine? As far as I know... _no_. [Chances are pretty high](http://blog.rust-lang.org/2016/05/13/rustup.html) that Rust will become a good host platform for [wasm](https://github.com/webassembly) - the future binary format for the web.
7+
Hi there, I'm Donald. [I'm a JavaScript developer](https://github.com/donaldpipowitch) who wants to learn Rust and as a part of this process I'll write here about my learnings. But what is Rust and **why do I want learn it**? Rust is a systems programming language like C or C++, but with influences from functional programming languages and even scripting languages like JavaScript. It _feels_ very modern - which is no surprise, because it is a relatively young language. [It went 1.0 in 2015!](http://blog.rust-lang.org/2015/05/15/Rust-1.0.html) That doesn't only mean it is _fun to write_, because it has less clutter to carry around, it is also _fun to use_, because it has a modern toolchain with a great package manager. Rust's most unique feature is probably the compile-time safety check: it catches errors like segfaults without introducing a garbage collector. Or to phrase it differently: maximum safety with maximum performance.
88

9-
Before we dive into our setup we want to look at least once into a real Rust file:
9+
Probably even more important than its features is the ecosystem and the community behind the language. Rust really shines here - especially for people who love the web. The language was (and still is) heavily influenced by developers from Mozilla. They have written [`servo`](https://github.com/servo/servo), a modern browser engine, in Rust and [parts of Firefox are now running Rust code](https://hacks.mozilla.org/2017/11/entering-the-quantum-era-how-firefox-got-fast-again-and-where-its-going-to-get-faster/). [Rust is also great for authoring WebAssembly code](https://www.rust-lang.org/what/wasm) (short: _Wasm_), a [binary format for the web](https://webassembly.org/), which is [supported in Firefox, Edge, Chrome and Safari](https://caniuse.com/#feat=wasm).
10+
11+
To summarize: Rust is a young modern language with a great tooling and ecosystem, good safety and performance promises and which can be used for a lot of different projects - from low level tasks to command line tools and even web projects.
12+
13+
Before we dive into our tutorial we want to look at least once into a real Rust file:
1014

1115
```rust
1216
fn main() {
@@ -16,28 +20,28 @@ fn main() {
1620

1721
The JavaScript equivalent _could roughly_ look like this:
1822

19-
```javascript
23+
```js
2024
function main() {
2125
console.log('Hello World!');
2226
}
2327
```
2428

2529
Nothing too scary, right? The `!` behind `println` could be a bit confusing, but don't mind it for now. Just think of it as a special function.
2630

27-
How do we move on from here? First I'll guide you how my current setup looks like to use Node and Rust. After that I'll create several kitchen sink like examples - first with Node and then with Rust. I'll try to explain them as best as I can, but _don't_ expect in-depth explanations in every case. Don't forget that I'm trying to learn Rust - _just like you_. Probably you need to explain _me_ some things, too! Oh, and before I forget it: my Node examples will be written in [TypeScript](https://www.typescriptlang.org/) actually! I think it makes some examples easier to compare to Rust and if you experience sweet type safety from Rust you want a little bit of that in your Node projects anyway ;)
31+
How do we move on from here? First I'll guide you how my current setup looks like to use Node and Rust. Many people seemed to like that I introduce some convenient tooling and IDE configurations _before_ actually speaking about Rust itself. But you can skip this chapter, if you want. After the setup step I'll create several kitchen sink like examples - first with Node and then with Rust. I'll try to explain them as best as I can, but _don't_ expect in-depth explanations in every case. Don't forget that I'm trying to learn Rust - _just like you_. Probably you need to explain _me_ some things, too! And before I forget it: my Node examples will be written in [TypeScript](https://www.typescriptlang.org/)! Writing them in TypeScript will make it a little bit easier to compare some examples to Rust.
2832

29-
I try to add an example every two weeks.
33+
One word about the structure of this tutorial before we start. Every chapter has its own directory. If a chapter has sub-chapters they also have sub-directories. And if a (subd-)chapter contains code examples, you'll find a `node` and a `rust` directory which contain all the code of this (sub-)chapter. (One example: The chapter [_"Package Manager"_](package-manager/README.md) can be found inside [`package-manager/`](package-manager). It has the sub-chapter [_"Publishing"_](package-manager/README.md#publishing) and the corresponding code examples can be found in [`package-manager/publishing/node/`](package-manager/publishing/node) and [`package-manager/publishing/rust/`](package-manager/publishing/rust).)
3034

3135
# Table of contents
3236

33-
0. [Setup](setup/README.md)
34-
0. [Hello World](hello-world/README.md)
35-
0. [Package Manager](package-manager/README.md)
36-
0. [Read files](read-files/README.md)
37-
0. [Write files](write-files/README.md)
38-
0. [HTTP requests](http-requests/README.md)
39-
0. [Parse JSON](parse-json/README.md)
37+
1. [Setup](setup/README.md)
38+
2. [Hello World](hello-world/README.md)
39+
3. [Package Manager](package-manager/README.md)
40+
4. [Read files](read-files/README.md)
41+
5. [Write files](write-files/README.md)
42+
6. [HTTP requests](http-requests/README.md)
43+
7. [Parse JSON](parse-json/README.md)
4044

41-
Thank you for reading this article. ♥
45+
Thank you for reading this tutorial. ♥
4246

4347
I highly appreciate pull requests for grammar and spelling fixes as I'm not a native speaker. Thank you!

hello-world/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
Ah, yes! A classic _"Hello world!"_ example. This one will be really quick, but I'll show you an important difference between Node and Rust.
44

5-
Create a `hello-world.js` containing nothing more than this line:
5+
Create a [`hello-world.js`](hello-world/node/hello-world.js) containing nothing more than this line:
66

7-
```javascript
7+
```js
88
console.log('Hello world!');
99
```
1010

@@ -17,31 +17,31 @@ Hello world!
1717

1818
_Yeah!_ You'll see `Hello world!` in your console.
1919

20-
Now we'll do the same for Rust. Create a `hello_world.rs` with the followind content:
20+
Now we'll do the same for Rust. Create a [`hello_world.rs`](hello-world/rust/hello_world.rs) with the following content:
2121

2222
```rust
2323
fn main() {
2424
println!("Hello world!");
2525
}
2626
```
2727

28-
Rust actually needs a special entry point to execute code. This is our `main` function and as you can see a function in Rust is declared like in JavaScript, just with the `fn` keyword instead of `function`. It is important to call the function `main` or the Rust compiler will throw an error. In Rust we typically use 4 spaces to indent code inside a function. In JavaScript most projects I know (and [the Standard Style](https://github.com/feross/standard)) use 2 spaces. Rust also recommends `snake_case` naming style for directories and files while I think `kebab-case` is most common in JavaScript projects. `println` isn't a simple function call, but a macro - which is indicated by the `!`. For now think of a macro as some code which is transformed into other code at compile time. Last but not least you _need_ to wrap your string inside `"`, not `'`. In JavaScript there is no difference between `"` and `'` to create strings and [many](https://github.com/feross/standard) prefer to use `'`. In Rust a `"` creates a _string literal_ while `'` creates a _character literal_ which means it only accepts a single character. You could write `println!("H");` or `println!('H');` and both would compile, but `println!('Hello World!');` throws an error.
28+
Rust actually needs a special entry point to execute code. This is our `main` function and as you can see a function in Rust is declared like in JavaScript, but with the `fn` keyword instead of `function`. It is important to call the function `main` or the Rust compiler will throw an error. In Rust we typically use 4 spaces to indent code inside a function, while 2 spaces are more common for JavaScript projects. (But thankfully this is covered by prettier anyway and it could be covered by `rustfmt` when [my feature request will be solved](https://github.com/rust-lang/rls/issues/1198).) Rust also recommends `snake_case` naming style for directories and files while I think `kebab-case` is most common in JavaScript projects. `println` isn't a simple function call, but a macro - which is indicated by the `!`. For now think of a macro as some code which is transformed into other code at compile time. Last but not least you _need_ to wrap your string inside `"`, not `'`. In JavaScript there is no difference between `"` and `'` to create strings (and [many](https://github.com/feross/standard) prefer to use `'`, even though it's not prettiers default). In Rust a `"` creates a _string literal_ while `'` creates a _character literal_ which means it only accepts a _single character_. You could write `println!("H");` or `println!('H');` and both would compile, but `println!('Hello World!');` throws an error.
2929

3030
Now compile our code with the following command:
3131

3232
```bash
3333
$ rustc hello-word.rs
3434
```
3535

36-
You'll see... nothing on your console. Instead a new file called `hello-world` was created next to `hello-world.rs`. This is our compiled code. You can run it like this:
36+
You'll see... nothing on your console. Instead a new file called `hello-world` was created next to `hello-world.rs`. This file contains our compiled code. You can run it like this:
3737

3838
```bash
3939
$ ./hello-world
4040
Hello world!
4141
```
4242

43-
Now you'll see `Hello world!` in your console. This shows a fundamental difference between JavaScript/Node and Rust. Rust needs to be compiled before our program can be executed. This extra step is not needed for JavaScript which makes the development cycle with JavaScript sometimes faster. However the compilation step catches a ton of bugs _before_ even executing your program. This can be _so_ useful that you probably often want to introduce something similar to JavaScript - like TypeScript. There is another big benefit: we can easily share our compiled `hello-world` program with other developers _without_ the need for them to have Rust installed. This is not possible with Node scripts. Everyone who wants to run our `hello-world.js` needs to have Node installed.
43+
Now you'll see `Hello world!` in your console. This shows a fundamental difference between JavaScript/Node and Rust. Rust needs to be compiled before our program can be executed. This extra step is not needed for JavaScript which makes the development cycle with JavaScript sometimes faster. However the compilation step catches a ton of bugs _before_ even executing your program. This can be _so_ useful that you probably want to introduce a similar sanity check to JavaScript - for example by using TypeScript. There is another big benefit: we can easily share our compiled `hello-world` program with other developers _without_ the need for them to have Rust installed. This is not possible with Node scripts. Everyone who wants to run our `hello-world.js` needs to have Node installed and in a version which is supported by our script.
4444

45-
______
45+
---
4646

47-
[prev](../setup/README.md) | [next](../package-manager/README.md)
47+
[prev _"Setup"_](../setup/README.md) | [next _"Package Manager"_](../package-manager/README.md)

hello-world/rust/hello_world

-297 KB
Binary file not shown.

http-requests/README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ Because GitHubs API is served over `https` we'll use Node's `https` module. We c
88

99
So this is our basic example:
1010

11-
```typescript
11+
```ts
1212
import { get } from 'https';
1313

1414
const host = 'api.github.com';
1515
const path = '/users/donaldpipowitch';
1616

1717
get({ host, path }, (res) => {
1818
let buf = '';
19-
res.on('data', (chunk) => buf = buf + chunk);
19+
res.on('data', (chunk) => (buf = buf + chunk));
2020
res.on('end', () => console.log(`Response: ${buf}`));
21-
}).on('error', (err) => { throw `Couldn't send request.` });
21+
}).on('error', (err) => {
22+
throw `Couldn't send request.`;
23+
});
2224
```
2325

2426
We import the `get` function from `https`. We declare a `host` and `path` (no need to set the protocol, when we already use the `https` module). After that we call `get` and pass an options object (containing our `host` and `path`) and callback whic accepts a response object (`res`) as the _first_ parameter. Yes, `get` doesn't follow the usual callback style pattern of Node where the first param is an error and the second param is a result. It is more low level than that. Instead we have an request object (the return value of `get`) and an response object (`res`) which are both event emitters. We listen for `error` events on the request object and in case of an error we just `throw` `Couldn't send request.` to exit our program.
@@ -66,7 +68,7 @@ get({ host, path }, (res) => {
6668
+ }
6769
+ });
6870
}).on('error', (err) => { throw `Couldn't send request.` });
69-
````
71+
```
7072

7173
Test the program again:
7274

@@ -240,7 +242,7 @@ After that we read our result into a buffer (`buf`) and print the response body.
240242
If you run our program now you see the same error as in our first Node example:
241243

242244
```
243-
$ cargo run -q
245+
$ cargo -q run
244246
Response: Request forbidden by administrative rules. Please make sure your request has a User-Agent header (http://developer.github.com/v3/#user-agent-required). Check https://developer.github.com for other possible causes.
245247
```
246248

@@ -278,7 +280,7 @@ Note that we use an `if` statement in Rust for the first time. Unlike JavaScript
278280
Test the program again:
279281

280282
```
281-
$ cargo run -q
283+
$ cargo -q run
282284
Response: Request forbidden by administrative rules. Please make sure your request has a User-Agent header (http://developer.github.com/v3/#user-agent-required). Check https://developer.github.com for other possible causes.
283285
284286
thread '<main>' panicked at 'Got client error: 403 Forbidden', src/main.rs:50
@@ -332,12 +334,12 @@ We import `Headers` and `UserAgent` from `hyper::header`. We create a new instan
332334
The last thing we need to do is passing our `headers` to our actually request with the `headers` method, just before we call `send`. Done!
333335

334336
```
335-
$ cargo run -q
337+
$ cargo -q run
336338
Response: {"login":"donaldpipowitch","id":1152805, ...
337339
```
338340

339341
The Node and the Rust example both show the same result now. Nice. In the next example I'll show you how to actually handle a JSON response.
340342

341-
______
343+
---
342344

343-
[prev](../write-files/README.md) | [next](../parse-json/README.md)
345+
[prev _"Write files"_](../write-files/README.md) | [next _"Parse JSON"_](../parse-json/README.md)

http-requests/rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "http-requests"
33
version = "1.0.0"
44
publish = false
5+
edition = "2018"
56

67
[dependencies]
78
hyper = "0.9.0"

0 commit comments

Comments
 (0)