@@ -1432,6 +1432,86 @@ building our guessing game, but we need to know how to do one last thing first:
1432
1432
get input from the keyboard. You can't have a guessing game without the ability
1433
1433
to guess!
1434
1434
1435
+ # Strings
1436
+
1437
+ Strings are an important concept for any programmer to master. Rust's string
1438
+ handling system is a bit different than in other languages, due to its systems
1439
+ focus. Any time you have a data structure of variable size, things can get
1440
+ tricky, and strings are a re-sizable data structure. That said, Rust's strings
1441
+ also work differently than in some other systems languages, such as C.
1442
+
1443
+ Let's dig into the details. A ** string** is a sequence of unicode scalar values
1444
+ encoded as a stream of UTF-8 bytes. All strings are guaranteed to be
1445
+ validly-encoded UTF-8 sequences. Additionally, strings are not null-terminated
1446
+ and can contain null bytes.
1447
+
1448
+ Rust has two main types of strings: ` &str ` and ` String ` .
1449
+
1450
+ The first kind is a ` &str ` . This is pronounced a 'string slice.' String literals
1451
+ are of the type ` &str ` :
1452
+
1453
+ ``` {rust}
1454
+ let string = "Hello there.";
1455
+ ```
1456
+
1457
+ This string is statically allocated, meaning that it's saved inside our
1458
+ compiled program, and exists for the entire duration it runs. The ` string `
1459
+ binding is a reference to this statically allocated string. String slices
1460
+ have a fixed size, and cannot be mutated.
1461
+
1462
+ A ` String ` , on the other hand, is an in-memory string. This string is
1463
+ growable, and is also guaranteed to be UTF-8.
1464
+
1465
+ ``` {rust}
1466
+ let mut s = "Hello".to_string();
1467
+ println!("{}", s);
1468
+
1469
+ s.push_str(", world.");
1470
+ println!("{}", s);
1471
+ ```
1472
+
1473
+ You can coerce a ` String ` into a ` &str ` with the ` as_slice() ` method:
1474
+
1475
+ ``` {rust}
1476
+ fn takes_slice(slice: &str) {
1477
+ println!("Got: {}", slice);
1478
+ }
1479
+
1480
+ fn main() {
1481
+ let s = "Hello".to_string();
1482
+ takes_slice(s.as_slice());
1483
+ }
1484
+ ```
1485
+
1486
+ To compare a String to a constant string, prefer ` as_slice() ` ...
1487
+
1488
+ ``` {rust}
1489
+ fn compare(string: String) {
1490
+ if string.as_slice() == "Hello" {
1491
+ println!("yes");
1492
+ }
1493
+ }
1494
+ ```
1495
+
1496
+ ... over ` to_string() ` :
1497
+
1498
+ ``` {rust}
1499
+ fn compare(string: String) {
1500
+ if string == "Hello".to_string() {
1501
+ println!("yes");
1502
+ }
1503
+ }
1504
+ ```
1505
+
1506
+ Converting a ` String ` to a ` &str ` is cheap, but converting the ` &str ` to a
1507
+ ` String ` involves allocating memory. No reason to do that unless you have to!
1508
+
1509
+ That's the basics of strings in Rust! They're probably a bit more complicated
1510
+ than you are used to, if you come from a scripting language, but when the
1511
+ low-level details matter, they really matter. Just remember that ` String ` s
1512
+ allocate memory and control their data, while ` &str ` s are a reference to
1513
+ another string, and you'll be all set.
1514
+
1435
1515
# Standard Input
1436
1516
1437
1517
Getting input from the keyboard is pretty easy, but uses some things
@@ -3614,6 +3694,94 @@ guide](http://doc.rust-lang.org/guide-pointers.html#rc-and-arc).
3614
3694
3615
3695
# Patterns
3616
3696
3697
+ # Method Syntax
3698
+
3699
+ Functions are great, but if you want to call a bunch of them on some data, it
3700
+ can be awkward. Consider this code:
3701
+
3702
+ ``` {rust,ignore}
3703
+ baz(bar(foo(x)));
3704
+ ```
3705
+
3706
+ We would read this left-to right, and so we see 'baz bar foo.' But this isn't the
3707
+ order that the functions would get called in, that's inside-out: 'foo bar baz.'
3708
+ Wouldn't it be nice if we could do this instead?
3709
+
3710
+ ``` {rust,ignore}
3711
+ x.foo().bar().baz();
3712
+ ```
3713
+
3714
+ Luckily, as you may have guessed with the leading question, you can! Rust provides
3715
+ the ability to use this ** method call syntax** via the ` impl ` keyword.
3716
+
3717
+ Here's how it works:
3718
+
3719
+ ```
3720
+ struct Circle {
3721
+ x: f64,
3722
+ y: f64,
3723
+ radius: f64,
3724
+ }
3725
+
3726
+ impl Circle {
3727
+ fn area(&self) -> f64 {
3728
+ std::f64::consts::PI * (self.radius * self.radius)
3729
+ }
3730
+ }
3731
+
3732
+ fn main() {
3733
+ let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
3734
+ println!("{}", c.area());
3735
+ }
3736
+ ```
3737
+
3738
+ This will print ` 12.566371 ` .
3739
+
3740
+ We've made a struct that represents a circle. We then write an ` impl ` block,
3741
+ and inside it, define a method, ` area ` . Methods take a special first
3742
+ parameter, ` &self ` . There are three variants: ` self ` , ` &self ` , and ` &mut self ` .
3743
+ You can think of this first parameter as being the ` x ` in ` x.foo() ` . The three
3744
+ variants correspond to the three kinds of thing ` x ` could be: ` self ` if it's
3745
+ just a value on the stack, ` &self ` if it's a reference, and ` &mut self ` if it's
3746
+ a mutable reference. We should default to using ` &self ` , as it's the most
3747
+ common.
3748
+
3749
+ Finally, as you may remember, the value of the area of a circle is ` π*r² ` .
3750
+ Because we took the ` &self ` parameter to ` area ` , we can use it just like any
3751
+ other parameter. Because we know it's a ` Circle ` , we can access the ` radius `
3752
+ just like we would with any other struct. An import of π and some
3753
+ multiplications later, and we have our area.
3754
+
3755
+ You can also define methods that do not take a ` self ` parameter. Here's a
3756
+ pattern that's very common in Rust code:
3757
+
3758
+ ```
3759
+ struct Circle {
3760
+ x: f64,
3761
+ y: f64,
3762
+ radius: f64,
3763
+ }
3764
+
3765
+ impl Circle {
3766
+ fn new(x: f64, y: f64, radius: f64) -> Circle {
3767
+ Circle {
3768
+ x: x,
3769
+ y: y,
3770
+ radius: radius,
3771
+ }
3772
+ }
3773
+ }
3774
+
3775
+ fn main() {
3776
+ let c = Circle::new(0.0, 0.0, 2.0);
3777
+ }
3778
+ ```
3779
+
3780
+ This ** static method** builds a new ` Circle ` for us. Note that static methods
3781
+ are called with the ` Struct::method() ` syntax, rather than the ` ref.method() `
3782
+ syntax.
3783
+
3784
+
3617
3785
# Closures
3618
3786
3619
3787
So far, we've made lots of functions in Rust. But we've given them all names.
@@ -4318,6 +4486,152 @@ the same function, so our binary is a little bit larger.
4318
4486
4319
4487
# Tasks
4320
4488
4489
+ Concurrency and parallelism are topics that are of increasing interest to a
4490
+ broad subsection of software developers. Modern computers are often multi-core,
4491
+ to the point that even embedded devices like cell phones have more than one
4492
+ processor. Rust's semantics lend themselves very nicely to solving a number of
4493
+ issues that programmers have with concurrency. Many concurrency errors that are
4494
+ runtime errors in other languages are compile-time errors in Rust.
4495
+
4496
+ Rust's concurrency primitive is called a ** task** . Tasks are lightweight, and
4497
+ do not share memory in an unsafe manner, preferring message passing to
4498
+ communicate. It's worth noting that tasks are implemented as a library, and
4499
+ not part of the language. This means that in the future, other concurrency
4500
+ libraries can be written for Rust to help in specific scenarios. Here's an
4501
+ example of creating a task:
4502
+
4503
+ ``` {rust}
4504
+ spawn(proc() {
4505
+ println!("Hello from a task!");
4506
+ });
4507
+ ```
4508
+
4509
+ The ` spawn ` function takes a proc as an argument, and runs that proc in a new
4510
+ task. A proc takes ownership of its entire environment, and so any variables
4511
+ that you use inside the proc will not be usable afterward:
4512
+
4513
+ ``` {rust,ignore}
4514
+ let mut x = vec![1i, 2i, 3i];
4515
+
4516
+ spawn(proc() {
4517
+ println!("The value of x[0] is: {}", x[0]);
4518
+ });
4519
+
4520
+ println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
4521
+ ```
4522
+
4523
+ ` x ` is now owned by the proc, and so we can't use it anymore. Many other
4524
+ languages would let us do this, but it's not safe to do so. Rust's type system
4525
+ catches the error.
4526
+
4527
+ If tasks were only able to capture these values, they wouldn't be very useful.
4528
+ Luckily, tasks can communicate with each other through ** channel** s. Channels
4529
+ work like this:
4530
+
4531
+ ``` {rust}
4532
+ let (tx, rx) = channel();
4533
+
4534
+ spawn(proc() {
4535
+ tx.send("Hello from a task!".to_string());
4536
+ });
4537
+
4538
+ let message = rx.recv();
4539
+ println!("{}", message);
4540
+ ```
4541
+
4542
+ The ` channel() ` function returns two endpoints: a ` Receiver<T> ` and a
4543
+ ` Sender<T> ` . You can use the ` .send() ` method on the ` Sender<T> ` end, and
4544
+ receive the message on the ` Receiver<T> ` side with the ` recv() ` method. This
4545
+ method blocks until it gets a message. There's a similar method, ` .try_recv() ` ,
4546
+ which returns an ` Option<T> ` and does not block.
4547
+
4548
+ If you want to send messages to the task as well, create two channels!
4549
+
4550
+ ``` {rust}
4551
+ let (tx1, rx1) = channel();
4552
+ let (tx2, rx2) = channel();
4553
+
4554
+ spawn(proc() {
4555
+ tx1.send("Hello from a task!".to_string());
4556
+ let message = rx2.recv();
4557
+ println!("{}", message);
4558
+ });
4559
+
4560
+ let message = rx1.recv();
4561
+ println!("{}", message);
4562
+
4563
+ tx2.send("Goodbye from main!".to_string());
4564
+ ```
4565
+
4566
+ The proc has one sending end and one receiving end, and the main task has one
4567
+ of each as well. Now they can talk back and forth in whatever way they wish.
4568
+
4569
+ Notice as well that because ` Sender ` and ` Receiver ` are generic, while you can
4570
+ pass any kind of information through the channel, the ends are strongly typed.
4571
+ If you try to pass a string, and then an integer, Rust will complain.
4572
+
4573
+ ## Futures
4574
+
4575
+ With these basic primitives, many different concurrency patterns can be
4576
+ developed. Rust includes some of these types in its standard library. For
4577
+ example, if you wish to compute some value in the background, ` Future ` is
4578
+ a useful thing to use:
4579
+
4580
+ ``` {rust}
4581
+ use std::sync::Future;
4582
+
4583
+ let mut delayed_value = Future::spawn(proc() {
4584
+ // just return anything for examples' sake
4585
+
4586
+ 12345i
4587
+ });
4588
+ println!("value = {}", delayed_value.get());
4589
+ ```
4590
+
4591
+ Calling ` Future::spawn ` works just like ` spawn() ` : it takes a proc. In this
4592
+ case, though, you don't need to mess with the channel: just have the proc
4593
+ return the value.
4594
+
4595
+ ` Future::spawn ` will return a value which we can bind with ` let ` . It needs
4596
+ to be mutable, because once the value is computed, it saves a copy of the
4597
+ value, and if it were immutable, it couldn't update itself.
4598
+
4599
+ The proc will go on processing in the background, and when we need the final
4600
+ value, we can call ` get() ` on it. This will block until the result is done,
4601
+ but if it's finished computing in the background, we'll just get the value
4602
+ immediately.
4603
+
4604
+ ## Success and failure
4605
+
4606
+ Tasks don't always succeed, they can also fail. A task that wishes to fail
4607
+ can call the ` fail! ` macro, passing a message:
4608
+
4609
+ ``` {rust}
4610
+ spawn(proc() {
4611
+ fail!("Nope.");
4612
+ });
4613
+ ```
4614
+
4615
+ If a task fails, it is not possible for it to recover. However, it can
4616
+ notify other tasks that it has failed. We can do this with ` task::try ` :
4617
+
4618
+ ``` {rust}
4619
+ use std::task;
4620
+ use std::rand;
4621
+
4622
+ let result = task::try(proc() {
4623
+ if rand::random() {
4624
+ println!("OK");
4625
+ } else {
4626
+ fail!("oops!");
4627
+ }
4628
+ });
4629
+ ```
4630
+
4631
+ This task will randomly fail or succeed. ` task::try ` returns a ` Result `
4632
+ type, so we can handle the response like any other computation that may
4633
+ fail.
4634
+
4321
4635
# Macros
4322
4636
4323
4637
# Unsafe
0 commit comments