我的Rust編程第一課

題圖來(lái)源: Bio-Rust

在2020年5月17日,HengLi在它的一篇博客「Fast high-level programming languages」提到,他一直在尋找一門編程語(yǔ)言,生物學(xué)家容易使用而且速度還快。( I have always been searching for a high-level language that is fast and easy to use by biologists. )

于是在這篇博客中,他評(píng)估了一些高級(jí)編程語(yǔ)言的處理速度,包括,C, Python, Javascript, LuaJIT, Nim, Crystal,Rust。其中Rust在FASTQ的解析速度上略勝于C語(yǔ)言。

同時(shí)在2020年12月的nature的technology feature中也有一篇是關(guān)于Rust,「Why scientists are turning to Rust」地址為https://www.nature.com/articles/d41586-020-03382-2

里面有一張圖,是評(píng)估Rust近年來(lái)的社區(qū)狀態(tài)的(即相關(guān)包的增長(zhǎng)數(shù)量),從中可以發(fā)現(xiàn)Rust的增長(zhǎng)超過(guò)了R。

Rust社區(qū)活躍

我并不是某個(gè)編程語(yǔ)言的信徒,平常用的最多的是R和Python,同時(shí)經(jīng)常性的找機(jī)會(huì)學(xué)習(xí)C和C++,以及每隔幾個(gè)月會(huì)去嘗試學(xué)一門新的編程語(yǔ)言。

這一次,我是跟著極客時(shí)間里的一門課,「陳天·Rust編程第一課」學(xué)習(xí)Rust。
基礎(chǔ)配置:安裝Rust工具鏈

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

我使用VScode進(jìn)行開(kāi)發(fā),并安裝了如下插件

  • rust-analyzer (語(yǔ)法分析)
  • rust syntax (語(yǔ)法高亮)
  • crates
  • better toml (TOML格式更好的展示)
  • rust test lens
  • Tabnine (基于機(jī)器學(xué)習(xí)的自動(dòng)補(bǔ)全,不只是Rust)

接著,嘗試使用Rust構(gòu)建第一個(gè)程序。我的目標(biāo)是讀取Fasta,統(tǒng)計(jì)其中的A, T, C, G各有多少個(gè)。
完成這個(gè)需求,有兩個(gè)思路,第一個(gè)是調(diào)用成熟的庫(kù),第二個(gè)是自己造輪子寫一個(gè)函數(shù)。
對(duì)于思路1,我使用關(guān)鍵詞,Rust和Bio搜索到一個(gè)庫(kù)叫做,rust-bio。https://rust-bio.github.io/

接下來(lái),使用cargo new創(chuàng)建項(xiàng)目

cargo new fasta_count

第二步: 添加依賴。編輯 Cargo.toml , 添加依賴信息

[dependencies]
bio = "0.37.1"

第三步: 學(xué)習(xí)rust-bio文檔,查找相關(guān)函數(shù),然后在 src/main.rs中編寫代碼。

use bio::io::fasta;
use std::io;

fn main() {
    let  reader = fasta::Reader::new(io::stdin());
    let mut nb_a = 0;
    let mut nb_t = 0;
    let mut nb_c = 0;
    let mut nb_g = 0;
    for result in reader.records(){
        let record = result.expect("Error during fasta record parsing");
        for &base in record.seq() { //return sequence
            if base == b'a' || base == b'A' {
                nb_a += 1;
            } else if base == b'c' || base == b'C'{
                nb_c += 1;
            } else if base == b'g' || base == b'G'{ 
                nb_g += 1;
            } else if base == b't' || base == b'T'{ 
                nb_t += 1;
            }
        }
    }
    println!("A:{}, C:{}, G:{}, T:{}", nb_a, nb_c, nb_g, nb_t);
}

我使用標(biāo)準(zhǔn)庫(kù)io::stdin從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù),然后利用fasta::Reader的new出一個(gè)新的reader實(shí)例。對(duì)該實(shí)例的records對(duì)象進(jìn)行遍歷,得到fasta的中記錄,record。最后對(duì)記錄中序列進(jìn)行遍歷,得到不同堿基的數(shù)目。

第四步:編譯代碼。cargo會(huì)先將依賴環(huán)境下載到當(dāng)前項(xiàng)目下,然后在進(jìn)行編譯。
cargo build

編譯結(jié)果存放在 target的debug目錄下,名為fasta_count。我們運(yùn)行程序,得到結(jié)果。

cat TAIR10.fa | target/debug/fasta_count
# A:38223602, C:21551439, G:21528650, T:38177852

第一種思路的代碼,是看教程里使用案例"使用HTTP獲取HTML然后保存成Markdown"后,自己嘗試的第一個(gè)和生信相關(guān)程序。在嘗試過(guò)程中,由于對(duì)基本的數(shù)據(jù)類型不了解,所以在處理字符的時(shí)候,還專門去檢索了下 'a' 和 b'a'的區(qū)別,以及為什么要用一個(gè)b''.
鑒于自己的水平太次,還是決定后續(xù)學(xué)習(xí)更多Rust基礎(chǔ)再來(lái)嘗試吧。

最后說(shuō)說(shuō)自己的編程體驗(yàn):

每一門編程語(yǔ)言都有其特殊的語(yǔ)法,在Rust中,Rust用let對(duì)類型進(jìn)行推導(dǎo),而C++中是用auto進(jìn)行類型推導(dǎo)。Rust和Python類似,可以直接用for x in xxx對(duì)xxx進(jìn)行遍歷,而C++則是 for (auto x : xxx )。Rust使用{}聲明代碼塊,而不是Python那樣子使用縮進(jìn)。在函數(shù)返回上,Rust可以用return 顯示說(shuō)明要返回的內(nèi)容,還是隱式將最后一個(gè)值(不能加上;)作為返回值,這個(gè)跟R語(yǔ)言又很像。當(dāng)然還有函數(shù)定義,python用def 函數(shù)名, C和C++是返回值 函數(shù)名,R用 函數(shù)名 <-function, GO是 func 函數(shù)名, Rust用的是新的縮寫 fn 函數(shù)名。

每次我學(xué)一門編程語(yǔ)言的時(shí)候,我都在想,這種語(yǔ)法上的特立獨(dú)行,到底是為了什么呢?
吐槽完語(yǔ)言,最后夸夸Rust的編譯器。它的編譯器非常強(qiáng)大,能夠很好的指出的我代碼中的錯(cuò)誤,便于檢索debug。甚至有些時(shí)候都不需要檢索,因?yàn)樗鼤?huì)直接跟你說(shuō)怎么改。就仿佛有一個(gè)老師在你方便,跟你說(shuō),你這里不對(duì),你要這樣子做。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容