mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-02-06 02:53:28 +02:00
Simplify imports by importing fewer items directly (#2404)
When reading the code without an IDE, I find it useful to use explicit module names, especially when items come from the standard library. So `io::Error` instead of just `Error`, especially when people have just been told about `std::error::Error` as well. I also omitted most single-use items: I find it has less cognitive overhead to say “we import `fmt`” and then later use `fmt::Display` and `fmt::Formatter` in the code. It’s clear from the name that these two things have something to do with formatting. Finally, I made a few usages more consistent so that we refer to each item in the same way within a single codeblock.
This commit is contained in:
parent
7a462efb57
commit
1d7c9163f5
@ -7,9 +7,9 @@ minutes: 8
|
||||
Several crates have support for asynchronous channels. For instance `tokio`:
|
||||
|
||||
```rust,editable,compile_fail
|
||||
use tokio::sync::mpsc::{self, Receiver};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
async fn ping_handler(mut input: Receiver<()>) {
|
||||
async fn ping_handler(mut input: mpsc::Receiver<()>) {
|
||||
let mut count: usize = 0;
|
||||
|
||||
while let Some(_) = input.recv().await {
|
||||
|
@ -15,8 +15,7 @@
|
||||
// ANCHOR: solution
|
||||
// ANCHOR: Philosopher
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{self, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tokio::time;
|
||||
|
||||
struct Fork;
|
||||
@ -26,7 +25,7 @@ struct Philosopher {
|
||||
// ANCHOR_END: Philosopher
|
||||
left_fork: Arc<Mutex<Fork>>,
|
||||
right_fork: Arc<Mutex<Fork>>,
|
||||
thoughts: Sender<String>,
|
||||
thoughts: mpsc::Sender<String>,
|
||||
}
|
||||
|
||||
// ANCHOR: Philosopher-think
|
||||
|
@ -10,7 +10,7 @@ the system works correctly even when futures are cancelled. For example, it
|
||||
shouldn't deadlock or lose data.
|
||||
|
||||
```rust,editable,compile_fail
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};
|
||||
|
||||
@ -36,12 +36,12 @@ impl LinesReader {
|
||||
return Ok(None);
|
||||
}
|
||||
let s = String::from_utf8(bytes)
|
||||
.map_err(|_| io::Error::new(ErrorKind::InvalidData, "not UTF-8"))?;
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "not UTF-8"))?;
|
||||
Ok(Some(s))
|
||||
}
|
||||
}
|
||||
|
||||
async fn slow_copy(source: String, mut dest: DuplexStream) -> std::io::Result<()> {
|
||||
async fn slow_copy(source: String, mut dest: DuplexStream) -> io::Result<()> {
|
||||
for b in source.bytes() {
|
||||
dest.write_u8(b).await?;
|
||||
tokio::time::sleep(Duration::from_millis(10)).await
|
||||
@ -50,7 +50,7 @@ async fn slow_copy(source: String, mut dest: DuplexStream) -> std::io::Result<()
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
async fn main() -> io::Result<()> {
|
||||
let (client, server) = tokio::io::duplex(5);
|
||||
let handle = tokio::spawn(slow_copy("hi\nthere\n".to_owned(), client));
|
||||
|
||||
@ -102,7 +102,7 @@ async fn main() -> std::io::Result<()> {
|
||||
// ...
|
||||
let raw = std::mem::take(&mut self.bytes);
|
||||
let s = String::from_utf8(raw)
|
||||
.map_err(|_| io::Error::new(ErrorKind::InvalidData, "not UTF-8"))?;
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "not UTF-8"))?;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ avoid boilerplate when defining error types. It provides derive macros that
|
||||
assist in implementing `From<T>`, `Display`, and the `Error` trait.
|
||||
|
||||
```rust,editable,compile_fail
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
use std::io::Read;
|
||||
use std::{fs, io};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -28,9 +28,8 @@ higher-level errors.
|
||||
|
||||
```rust,editable
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
use std::io::Read;
|
||||
use std::{fmt, fs, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ReadUsernameError {
|
||||
@ -40,8 +39,8 @@ enum ReadUsernameError {
|
||||
|
||||
impl Error for ReadUsernameError {}
|
||||
|
||||
impl Display for ReadUsernameError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl fmt::Display for ReadUsernameError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::IoError(e) => write!(f, "I/O error: {e}"),
|
||||
Self::EmptyUsername(path) => write!(f, "Found no username in {path}"),
|
||||
@ -57,7 +56,7 @@ impl From<io::Error> for ReadUsernameError {
|
||||
|
||||
fn read_username(path: &str) -> Result<String, ReadUsernameError> {
|
||||
let mut username = String::with_capacity(100);
|
||||
File::open(path)?.read_to_string(&mut username)?;
|
||||
fs::File::open(path)?.read_to_string(&mut username)?;
|
||||
if username.is_empty() {
|
||||
return Err(ReadUsernameError::EmptyUsername(String::from(path)));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user