Rust標準輸入和輸出

2020-09-27 架構與人生

回顧一下我們寫的第一個 Rust 程序就是帶副作用的,其副作用就是向標準輸出(stdout),通常是終端或屏幕,輸出了 Hello, World! 讓屏幕上這幾個字符的地方點亮起來。println! 宏是最常見的輸出,用宏來做輸出的還有 print!,兩者都是向標準輸出(stdout)輸出,兩者的區別也一眼就能看出。至于格式化輸出,基礎運算符和字符串格式化小節有詳細說明,這裡就不再囉嗦了。

更通用的標準輸入與輸出定義在 std::io 模塊裡,調用 std::io::stdin() 和 std::io::stdout() 兩個函數分別會得到輸入句柄和輸出句柄(哎,句柄這個詞是計算機史上最莫名其妙的翻譯了),這兩個句柄默認會通過互斥鎖同步,也就是說不讓多個進程同時讀或寫標準輸入輸出,不然的話如果一個進程要往標準輸出畫馬,一個進程要畫驢,兩個進程同時寫標準輸出的話,最後可能就給畫出一頭騾子了,如果更多進程畫不同的動物最後可能就成四不像了。除了隱式地用互斥鎖,我們還可以顯式地在句柄上調用 .lock()。輸入輸出句柄實現了前面講的讀寫 Trait,所以是 reader/writer,就可以調接口來讀寫標準輸入與輸出了。舉幾個


慄子:

use std::io;fn read_from_stdin(buf: &mut String) -> io::Result<()> { try!(io::stdin().read_line(buf)); Ok(())}

use std::io;fn write_to_stdout(buf: &[u8]) -> io::Result<()> { try!(io::stdout().write(&buf)); Ok(())}

可以看到上面的例子都是返回了 io::Result<()> 類型,這不是偶然,而是 IO 操作通用的寫法,因為 IO 操作是程序與外界打交道,所以都是有可能失敗的,用 io::Result<T> 把結果包起來,io::Result<T> 只是標準 Result<T,E> 中 E 固定為 io::Error 後類型的別名,而作為有副作用的操作我們一般是不用關心其返回值的,因為執行這類函數其真正的意義都體現在副作用上面了,所以返回值只是用來表示是否成功執行,而本身 Result 類型本身已經可以表示執行狀態了,裡面的 T 是什麼則無關緊要,既然 T 沒什麼意義,那我們就選沒什麼意義的 unit 類型好了,所以 IO 操作基本上都是使用 io::Result<()>。

另外有一個地方需要注意的是由於 IO 操作可能會失敗所以一般都是和 try! 宏一起使用的,但是 try! 在遇到錯誤時會把錯誤 return 出去的,所以需要保證包含 try! 語句的函數其返回類型是 io::Result<T>,很多新手文檔沒仔細看就直接查 std api 文檔,然後照著 api 文檔裡面的例子把帶 IO 操作的 try! 宏寫到了 main 函數裡。結果一編譯,擦,照著文檔寫都編譯不過,什麼爛文檔。其實點一下 api 文檔上面的運行按鈕就會發現文檔裡面的例子都是把 try! 放在另一個函數裡面的,因為 main 函數是沒有返回值的,而 try! 會返回 io::Result<T>,所以直接把 try! 放 main 函數裡面肯定要跪。比如下面的從標準輸入讀取一行輸入,由於把 try! 放在了 main 函數裡,所以是編譯不過的。

use std::io;fn main() { let mut input = String::new(); try!(io::stdin().read_line(&mut input)); println!(&34;, input.trim());}

這裡有一件事需要主要的是 Rust 裡面沒有辦法從鍵盤獲取一個數字類型的值。實際上像 C 這樣的語言也不是直接獲取了數字類型,它只不過是做了一種轉換。那麼我們如果想要從鍵盤獲取一個數字類型應該怎麼做呢?

fn main() { let mut input = String::new(); std::io::stdin() .read_line(&mut input) .expect(&34;); // 這裡等效的寫法是: // let num: i32 = input.trim().parse().unwrap(); let num = input.trim().parse::<i32>().unwrap(); println!(&34;, num);}

如果有很多地方都需要輸入數字可以自行編寫一個 numin 宏:

macro_rules! numin { () =>{ { let mut input = String::new(); std::io::stdin() .read_line(&mut input) .expect(&34;); input.trim().parse().unwrap() } };}

於是上面的程序可以被改寫成:

fn main() { let num: i32 = numin!(); println!(&34;, num);}

不過如果用戶輸入的不是數字,那麼就會導致錯誤。這一點和 C 裡面是非常相似的。當然您可以把程序寫得再複雜一點兒來保證用戶輸入的一定是數字。不過這些就不是我們這一節要討論的內容了。

還有一點一些從其它語言轉過來的程式設計師可能會疑惑的是,如何從命令行接受輸入參數,因為 C 裡面的 main 函數可以帶參數所以可以直接從 main 函數的參數裡獲取輸入參數。但其實這類輸入與我們這裡講的有很大的差別的,它在 Rust 裡面被歸為環境變量,可以通過 std::env::args() 獲取,這個函數返回一個 Args 迭代器,其中第一個就是程序名,後面的都是輸入給程序的命令行參數。

use std::env;fn main() { let args = env::args(); for arg in args { println!(&34;, arg); }}

將上面的程序存為 args.rs 然後編譯執行,結果如下

$ rustc args.rs$ ./args a b c./argsabc

相關焦點

  • VS Code 搭建 Rust 開發環境
    上一篇文章安裝和配置好了 Rust 環境後,我們是使用的是簡單的文本工具編寫 Hello World 入門代碼,但是為了提高我們的學習效率,下面安利大家 VS Code 搭建 Rust 開發環境,讓我們開始享受 IDE 帶來的便利。
  • 一張圖帶您理解linux 的標準輸入和標準輸出
    通過一張圖帶您理解linux 的標準輸入輸出概念,這裡的終端處理程序代表作業系統內核。先給大家看一個很熟悉的例子:[root@testLinux ~]# ifconfig --查看網卡相關信息。,因此我們將這裡的這裡的鍵盤叫標準輸入,而輸出的結果通過顯示器顯示出來叫標準輸出,再來看下一個命令的輸出結果[root@testLinux ~]# cat /etc/cmss 由於這個文件夾不存在,因此系統輸出了錯誤的輸出,那麼我們就稱這種輸出叫標準錯誤輸出。
  • Linux環境下標準輸入、輸出、錯誤信息詳解
    Linux環境下標準輸入、輸出、錯誤信息詳解下面我們介紹在Linux環境下標準輸入、輸出、錯誤設備。標準輸入設備代號為0, 用來顯示輸入信息,標準輸出設備代號為1,用來顯示正常信息,標準錯誤設備代號為2,用來顯示錯誤信息。
  • Rust 語言技巧和竅門
    Racer,Clippy,rustfmt和fix這是非常好用的一組工具。Racer用來幫助你對rust代碼進行補全。,並檢查代碼是否符合rust慣用寫法,地道不地道、高效不高效?。安裝rustfmt,使用:rustup component add rustfmt然後工作區中運行rustfmt:cargo fmt。
  • 有了這個,不用安裝軟體也可以學 Rust
    可以按照自己的喜好進行編輯讓我們在這裡花一分鐘來解釋 GitHub Actions 是如何工作的,默認的 rust.yml 文件顯示:每當用戶將代碼壓入或接受 PR 到存儲庫中時,就會觸發 rust.yml 工作流 action。
  • Rust 學習筆記-6 有趣的字符串
    (&34;, company, location);}fn main() { demo20();}上面2段程序輸出的結果是一樣的.它被定義為標準庫pub struct String中的公共結構。字符串是一個可增長的集合。它是可變的UTF-8編碼類型。字符串對象類型可用於表示在運行時提供的字符串值。字符串對象在堆中分配。實際上是一個vector.語法:創建一個字符串對象.String::new()創建一個空白字符串對象.
  • 快速搜索 Rust 文檔、屬性和庫的瀏覽器插件
    大家好,Rust Search Extension是我從2018年開始開發的瀏覽器插件,方便大家在瀏覽器地址欄快速搜索官方文檔、內置屬性、crates和錯誤碼實時搜索top 10K的crates輸入關鍵字就能搜索下載量排名前10K的crates(crates.io上總共35+K個crate),並且每一個小時會提供最新的crates索引文件。
  • PLC輸入埠和輸出埠工作原理與接線
    PLC輸入埠和輸出埠工作原理 輸入輸出接口是plc和工業控制現場各類信號連接的部分。輸入口用來接受生產過程的各種參數。輸出口用來送出可編程控制器運算後得出的控制信息,並通過機外的執行機構完成工業現場各類控制。
  • Python輸入,輸出,存儲器和異常
    輸入/輸出程序與用戶的交互需要使用輸入/輸出,主要包括控制臺和文件;對於控制臺可以使用input和print。input(xxx)輸入xxx, 然後讀取用戶的輸入並返回。In [1]: input()1Out[1]: '1'文件輸入/輸出可以使用file類打開一個文件,使用file的read、readline和write來恰當的讀寫文件。對文件讀寫能力取決於打開文件時使用的模式, 常用模式讀模式("r")寫模式("w")追加模式("a")文件操作之後需要調用close方法來關閉文件。
  • ...並且在進行這項工作之前,需要了解 Unix標準輸入/輸出 (I/O) 流。
    Unix標準輸入/輸出 (I/O) 流知識講解 文章中,我們會了解當您在 Shell 中使用 < 操作符將程序輸入重定向到文件時,就可以將該文件中的內容輸入到該程序的標準輸入 (stdin) 流。
  • 何時使用 Rust 和何時使用 Golang?
    在本教程中,我們將就 Golang 和 Rust 進行比較和對比,評估這兩種程式語言的性能,並發性,內存管理和整體開發人員體驗。我們還將概述這些元素,以幫助您一目了然地為項目選擇正確的語言。該基準測試遊戲[2]比較了 rust 和 golang 的不同算法,如二叉樹。
  • Rust 學習筆記-15 模塊化
    (&34;,name); }}fn main(){ movies::play(&34;.to_string());}輸出結果:Playing movie 天龍八部Use 關鍵詞use關鍵字用來導入公共模塊。
  • rust程式語言Orphan Rule孤兒規則淺析
    rust不支持C++函數重載, 但是卻支持通過trait實現的運算符重載,有取有舍,當然trait的能力還遠不止如此,可以說trait融入rust各個角落,優雅實現各種語言約束和擴展。 本次呢,我來簡單分析一下rust語言的孤兒規則,體會一下其如何有效限制隨意擴展問題。
  • 運算放大器電壓範圍:輸入和輸出
    系統設計人員通常會遇到有關運算放大器電源輸入和輸出電壓範圍能力的問題,它可能讓人感到疑惑,那麼我在這裡嘗試解決這個問題。
  • Rust 學習筆記-3 Hello World
    在您的終端中執行:D:\demo\rust>cargo new hello-world Created binary (application) `hello-world` package D:\demo\rust>cd hello-world這會生成一個名為 hello-world 的新目錄,其中包含以下文件
  • 從 Rust 開始入門 WebAssembly | WebAssembly 教程
    本文所用到的原始碼Repo請點擊:https://github.com/second-state/wasm-learning/tree/master/rust雖然 WebAssembly 支持多種程式語言,但迄今為止,
  • 都說Rust程式語言難學,那我們Ubuntu系統裡安裝下試試
    這個曾經很小眾的程式語言,發布以後近些年越來越受開發者和企業的認可。在大型項目底層開發等領域C/C++「一統江湖」的年代,Rust能媲美這兩種底層的強大的語言,實力著實不可小覷。安全、性能、並發等特性的優勢,讓使用過的開發者都讚不絕口,眾口一詞給出肯定的態度。不過與之相應的是,Rust程式語言的學習難度。
  • python基礎知識:輸出和輸入
    輸出python中變量的輸出# 列印提示print('hello world')print('給我的卡---印度語,你好的意思')格式化輸出<1>格式化操作的目的比如有以下代碼:pirnt("我今年10歲")pirnt("我今年11歲"
  • Rust 語言常用技巧匯集
    Racer,Clippy,rustfmt和fix這是非常好用的一組工具。Racer用來幫助你對rust代碼進行補全。安裝rustfmt,使用:rustup component add rustfmt然後工作區中運行rustfmt:cargo fmt。
  • c++的輸入與輸出
    c++輸入與輸出C++ 標準庫提供了一組豐富的輸入/輸出功能,本章將討論 C++ 編程中最基本和最常見的 I/O 操作。輸入輸出並不是c++語言的正式組成成分,c和c++沒有為輸入輸出提供專門的結構。在c語言中輸入輸出是通過調用scanf和printf 實現的,在c++中是通過調用流對象cin和cout實現的。