Rust by Example — страница 58 из 66

}

/*************************************************************************

* "Reduce" phase

*

* Collect our intermediate results, and combine them into a final result

************************************************************************/

// combine each thread's intermediate results into a single final sum.

//

// we use the "turbofish" ::<> to provide sum() with a type hint.

//

// TODO: try without the turbofish, by instead explicitly

// specifying the type of final_result

let final_result = children.into_iter().map(|c| c.join().unwrap()).sum::();

println!("Final sum result: {}", final_result);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Assignments

It is not wise to let our number of threads depend on user inputted data. What if the user decides to insert a lot of spaces? Do we really want to spawn 2,000 threads? Modify the program so that the data is always chunked into a limited number of chunks, defined by a static constant at the beginning of the program.

See also:

   • Threads

   • vectors and iterators

   • closures, move semantics and moveclosures

   • destructuring assignments

   • turbofish notation to help type inference

   • unwrap vs. expect

   • enumerate

Channels

Rust provides asynchronous channels for communication between threads. Channels allow a unidirectional flow of information between two end-points: the Sender and the Receiver.

use std::sync::mpsc::{Sender, Receiver};

use std::sync::mpsc;

use std::thread;

static NTHREADS: i32 = 3;

fn main() {

// Channels have two endpoints: the `Sender` and the `Receiver`,

// where `T` is the type of the message to be transferred

// (type annotation is superfluous)

let (tx, rx): (Sender, Receiver) = mpsc::channel();

let mut children = Vec::new();

for id in 0..NTHREADS {

// The sender endpoint can be copied

let thread_tx = tx.clone();

// Each thread will send its id via the channel

let child = thread::spawn(move || {

// The thread takes ownership over `thread_tx`

// Each thread queues a message in the channel

thread_tx.send(id).unwrap();

// Sending is a non-blocking operation, the thread will continue

// immediately after sending its message

println!("thread {} finished", id);

});

children.push(child);

}

// Here, all the messages are collected

let mut ids = Vec::with_capacity(NTHREADS as usize);

for _ in 0..NTHREADS {

// The `recv` method picks a message from the channel

// `recv` will block the current thread if there are no messages available

ids.push(rx.recv());

}

// Wait for the threads to complete any remaining work

for child in children {

child.join().expect("oops! the child thread panicked");

}

// Show the order in which the messages were sent

println!("{:?}", ids);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Path

The Path struct represents file paths in the underlying filesystem. There are two flavors of Path: posix::Path, for UNIX-like systems, and windows::Path, for Windows. The prelude exports the appropriate platform-specific Path variant.

A Path can be created from an OsStr, and provides several methods to get information from the file/directory the path points to.

Note that a Path is not internally represented as an UTF-8 string, but instead is stored as a vector of bytes (Vec). Therefore, converting a Path to a &str is not free and may fail (an Option is returned).

use std::path::Path;

fn main() {

// Create a `Path` from an `&'static str`

let path = Path::new(".");

// The `display` method returns a `Show`able structure

let _display = path.display();

// `join` merges a path with a byte container using the OS specific

// separator, and returns the new path

let new_path = path.join("a").join("b");

// Convert the path into a string slice

match new_path.to_str() {

None => panic!("new path is not a valid UTF-8 sequence"),

Some(s) => println!("new path is {}", s),

}

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Be sure to check at other Path methods (posix::Path or windows::Path) and the Metadata struct.

See also:

OsStr and Metadata.

File I/O

The File struct represents a file that has been opened (it wraps a file descriptor), and gives read and/or write access to the underlying file.

Since many things can go wrong when doing file I/O, all the File methods return the io::Result type, which is an alias for Result.

This makes the failure of all I/O operations explicit. Thanks to this, the programmer can see all the failure paths, and is encouraged to handle them in a proactive manner.

open

The open static method can be used to open a file in read-only mode.