Rust 學習筆記(1)

基本語法與結構

1
2
3
4
fu main() {
// output hello rust
println!("Hello, Rust!");
}
  • fn 定義函數的關鍵字。
  • main 函式為程式入口。
  • println!() 為呼叫 rust 的巨集。
  • ; 每一個指令結尾都需要一個分號,來表示指令的結束。
  • // 為單行註解。

變數與常數

不可變變數

在 Rust 中宣告變數的方式為 let <name> = <variable>,這個變數是不能被改變的。如果你試圖改變這個變數,你可能會得到 “cannot assign twice to immutable variable <name>” 的錯誤。

1
2
3
4
5
// Example
fn main() {
let name = "咪路";
let age = 18;
}

可變變數

在 Rust 中想要改變變數,可以在宣告時使用 let mut,讓它們可以被改變的。

1
2
3
4
5
// Example
fn main() {
let mut age = 18;
age = age + 1;
}

常數

大多數的語言當中,都有常數(constant) 的用法。在 Rust 中,宣告常數的方法為 const PI: f32 = 3.1415926,而在 Rust 中宣告常數必須給定類型 (f32 為 32 位元的浮點數表示)。

1
2
3
4
5
// Example
fn main() {
const PI: f32 = 3.1415926;
const LN2: f32 = 0.693147;
}

資料型別

在剛剛的常數中提到,常數的宣告必須給定資料類型,而一般用 let 或是 let mut 也可以將類型給宣告進去,其方法是在變數名稱後面加上 : <type>

以下我們介紹在 Rust 中的型別。

純量型別 - scalar

  1. 整數
    在整數的類型中分為帶號整數(signed) 與非帶號整數 (unsigned),在這兩者中有可以分為 8-bits, 16-bits, 32-bits, 64-bits, 128-bits 與系統架構位元數,表示方法如下:
Length signed unsigned
8-bits i8 u8
16-bits i16 u16
32-bits i32 u32
64-bits i64 u64
128-bits i128 u128
arch isize usize

並且可以用各種方始表達整數數值。如果數值長度太長可以運用 _ 來增加可讀性。

  • 十進位:一般表達方式。
  • 八進位:在數值前面加上前綴 0o
  • 十六進位:在數值前面加上前綴 0x
  • 二進位:在數值前面加上前綴 0b
1
2
3
4
5
6
7
// Example
fn main() {
let a: u8 = 12;
let b: i16 = 0o12;
let c: i32 = 0x9912_4F3A;
let d: isize = 0b1010111_10110110;
}
  1. 浮點小數
    幅點小數則分為 f32f64 分別表示 32 位元與 64 位元。
1
2
3
4
// Example
fn main() {
const PI: f32 = 3.1415926;
}
  1. 布林值
    布林值則使用 bool 表示。
1
2
3
4
// Example
fn main() {
let a: bool = true;
}
  1. 字元
    字元用 char 表示。
1
2
3
4
// Example
fn main() {
let a: char = '咪';
}

複合型別 - compound

  1. Tuple

由多個數值組成,每個數值的資料型別不一定要一致,使用方法為利用小括號將數值包起來,並使用逗號分隔開來。
我們可以利用 <tuple_name>.<index> 來存取 Tuple 裡的數值。也可以用 pattern matching 的方式拆成多個變數。

1
2
3
4
5
6
7
// Example
fn main() {
let a: (u8, f32, char) = (3, 3.14, 'P');
let (x, y, z) = a;

println!("The first value in a is {}.", a.0);
}

另外,一個空的 Turple 叫做 Unit,這通常代表一個空的數值或是空的回傳型別。

  1. Array

而 Array 與 Tuple 不同的是 Tuple 可以由多個型別組成,而 Array 的所有數值必須是相同的型別,使用方法為用中括號將多個數值刮起來,並用透好隔開。

並且我們可以用 [<type | value>; <count>] 來表示 <count><type> 的陣列,也可以用來表示一個有 <count><value> 的陣列。

存取上與其他大多數的語言一樣用 <array_name>[<index>];

1
2
3
4
5
6
// Example
fn main() {
let a: [u8; 5] = [1, 2, 3, 4, 5];
let b = [true; 5];
println!(b[3]); // true
}

使用者輸入

當我們要讀取使用者輸入時,必須先標準函式庫(std)中的 io 函式庫。

1
use std:io

接著我們使用函式庫中的 stdin 函式,這個函式會回傳 std::io::Stdin 的物件,其中有 read_line 函式,用來讀取一行輸入。

最後 readl_line 會回傳一個 Result,這是一個 enums,並且可能為 OkErr,並且有 expect 的函示,用來處理錯誤訊息。

1
2
3
4
5
6
7
8
9
10
11
use std:io

fn main() {
let mut user = String::new();

io::stdin()
.read_line(&mut user)
.expect("Read line failed!");

println!(user);
}

若你使用 expect,程式仍能編譯,但是會產生一個警告 (warning)。


參考資料:

Rust 學習筆記(0)

Install Rust

在 MacOS, Linux 或是 Unix 家族的作業系統可以直接利用指令安裝

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

如果是 Windows 的話,可以參考官網

Hello, Rust!

Rust 是編譯式語言,在執行前需要進行編譯。

1
2
3
4
/* main.rs */
fn main() {
println!("Hello, Rust!");
}

我們可以使用 rustc 指令來進行編譯。

1
$ rustc main.rs

編譯完之後會得到一個可以執行的執行檔了。

利用 Cargo 建製

Cargo 是一個 Rust 的套件管理工具,在我們安裝 Rust 的同時,Cargo 也會被安裝至電腦中。

Cargo 具有許多幫助開發專案的功能,大多數的 Rust 專案也都會使用 Cargo 進行建製。

這裡只做簡單的介紹,更多資訊可以參考文件

利用 Cargo 建立專案

可以利用以下指令建立一個新的專案。

1
cargo new <專案名稱>

這個指令會幫我們建立一個資料夾,並在資料夾當中生成以下結構的檔案。

1
2
3
4
5
6
<專案名稱>
├── Cargo.toml
├── .gitignore
├── .git
└── src
└── main.rs
  • Cargo.toml: 紀錄專案資訊的檔案。
  • src: 放置程式原始碼的資料夾。
  • main.rs: 程式進入點。
  • .git & .gitignore: 版本控制相關。

編譯專案

編譯專案的指令為 cargo build
編譯完之後會將執行檔生成在 target/debug 的資料夾中。
另外 build 指令會下載紀錄在 Cargo.toml 的依賴函式庫,並生成 Cargo.lock 檔案。因此我們也可以利用這個指令來同步下載專案的依賴。

cargo build 指令預設上是 debug 模式,如果要發布專案,可以在指令中加入參數 --release 使用 release 模式。

執行專案

我們可以直接執行上面編譯出來的執行檔案,或是利用 cargo run 來執行。


參考資料:

2023 日本遊記

好像有將近 10 年沒有離開台灣了~當了太久的井底蛙,終於找到機會可以出國旅遊

Dec 20, 2023 - Japan Hokkaido

不過好死不死安排這幾天居然是學校的期末考(?
期末什麼的都交給同組的隊友
剩下的就祈禱老師不要當我了

中華航空 CI310 從桃園機場飛往新千歲機場
出發前我對華航的觀感不太好(?
但是大家問我為什麼我自己也說不太準
直到上了飛機,原來是…
空姊不夠正 RRR

新千歲機場位於日本的千歲市
走出機場就感受到了冬天的北海道
有點像是走在冰庫裡
但距離想像還有點差距
總覺得「哎呀!也沒多冷嘛~」
但我錯了…走完五天的行程之後
「這根本不是人待的地方」
「It’s fking cold」

北海道緯度較高
約略下午 4 點就開始天黑了
又因地廣人稀
即時我們到達之後就直奔飯店
抵達的時候也已經天黑了
用過餐之後我們到附近便利商店買點飲料
想說可以展現叫瓜瓜(日文系的同學)幫我惡補的日文了
但我只學了 1~99 怎麼講
在日本幾乎沒有 100 元以內的商品R
所以直到最後一天我也沒用上瓜瓜教我的日文

MQTT(0) 基本介紹

嗨!又好長一段時間沒寫文了(其實根本就沒寫幾篇)

前陣子 Boss 要我準備一堂 IoT 相關的課程,並且要教大家怎麼架設 MQTT Broker。
也就是說…學弟妹在老闆課堂上看到的簡報或是程式範例,可能是我做的~
為了造福學弟妹日後的作業…

什麼是 MQTT ?

MQTT 為 Message Queuing Telemetry Transport 的縮寫,它是一個基於發布/訂閱架構的傳輸協定(ISO/IEC 20922),並且具有輕量雙向以及高擴展性的特性,因此廣泛的應用在物聯網之中。

MQTT 的運作模式

在 MQTT 當中分為 MQTT broker 以及 MQTT client 兩個角色。MQTT Broker 通常不會主動傳輸訊息,而是作為訊息代理,有點像是小時候的傳直條,請旁邊的同學幫忙傳給心儀的對象,而這位同學的角色就像是 MQTT Broker,負責發訊息與收訊息的就是 MQTT client 啦!

大家都來找同一個 Broker 傳訊息,要怎麼知道哪一張紙條要傳到哪裡呢?這就要提到 MQTT 的主題(topic)。MQTT client 可以向 Broker 訂閱特定主題,當 Broker 收到訊息時,會根據主題,將訊息派發給有訂閱的 MQTT Client。


MQTT 的主題(Topic)

MQTT 的主題使用 ufw-8 編碼,並以斜線字元區分節層。基本上都沒有什麼太大的限制,最大的限制就是必須在 65,535 bits 之內。
舉個例子:

  • my-house/living-room/temperature
  • school/room-106/switch

MQTT 也有一些比較特殊的字元,像是:

  • +: 作為單層的通用字元,用來表示該層級所有主題。
    舉例來說:A/B/+
    可以匹配下列主題
    - A/B/C
    - A/B/Y
    但是與下列主題不相符
    - A/C/D
    - A/B/C/D

  • #: 為多層的通用字元,表示該層級以下的所有主題。
    舉例來說:A/B/#
    可以匹配下列主題
    - A/B/C
    - A/B/Y
    - A/B/C/D
    但是與下列主題不相符
    - A/C/D

  • $: 通常為系統控制的字元。主要用於獲取 MQTT Broker 的運作狀態、連線資訊或是運行紀錄等資料。

參考資料:

Linux 基本指令(0)

之所以會有這幾篇是因為…

我要幫團員上課,所以做了一點上課的小筆記。

檔案操作相關

指令 功能
cd 變更工作目錄(資料夾)
cp 複製檔案
ls 列出當前目錄(資料夾)的檔案
mkdir 建立目錄(資料夾)
mv 更改檔案名稱或是移動檔案
pwd 顯示當前的目錄(資料夾)
rm 刪除檔案
rmdir 刪除目錄(資料夾)
  1. cd: 變更工作目錄(資料夾)

    1
    $ cd <目錄名稱>
  2. ls: 列出當前目錄(資料夾)的檔案

    1
    $ ls <目錄名稱>

    沒有給定目錄的話,預設是當前的目錄。
    如果是以 ‘.’ 開頭的檔案,在 Linux 家族當中為隱藏檔案,一般使用 ls 不會顯示。
    可以搭配參數來顯示隱藏檔案

    1
    2
    3
    $ ls --all <目錄名稱>
    # or
    $ ls -a <目錄名稱>
  3. mkdir: 建立目錄(資料夾)

    1
    $ mkdir <目錄名稱1>, <目錄名稱2>....
  4. rmdir: 刪除目錄(資料夾)

    1
    $ rmdir <目錄名稱1>, <目錄名稱2>....

    通常只能刪除空的目錄。

  5. rm: 刪除檔案

    1
    $ rm <檔案1>, <檔案2>...

    如果要讓指令刪除目錄以及目錄裡的所有東西,可以使用遞迴處理(-r)的參數。

    1
    2
    3
    $ rm --recursive <檔案1>, <檔案2>...
    # or
    $ rm -r <檔案1>, <檔案2>...
  6. cp: 複製檔案

    1
    $ cp <要複製的目標> <複製的目的地>

    如果要複製目錄的話,同樣可以利用遞迴處理的參數。

    1
    2
    3
    $ cp --recursive <要複製的目標> <複製的目的地>
    # or
    $ cp -r <要複製的目標> <複製的目的地>
  7. mv: 更改檔案名稱或是移動檔案

    1
    $ mv <移動的目標> <移動的目的>

    其實更改名稱與移動檔案,都是更改路徑。

    1
    2
    3
    4
    # 移動 test.txt 到 temp 資料夾
    $ mv test.txt temp/
    # 將 test.txt 更改檔名為 test.cpp
    $ mv test.txt test.cpp
  8. pwd: 顯示當前的目錄(資料夾)

    1
    pwd # 非常單純,就是這樣

更多的檔案操作?

指令 功能
cat 顯示檔案的內容
head 顯示檔案前面幾行的內容
less 利用分頁模式檢視檔案內容
ln 建立連結(捷徑)
tail 顯示檔案後面幾行的內容
touch 建立檔案
  1. cat: 顯示檔案的內容

    1
    $ cat <檔案名稱>
  2. head: 顯示檔案前面幾行的內容

    1
    $ head <檔案名稱>

    通常預設會顯示 10 行。可以透過 --line 參數設定。

    1
    2
    3
    $ head --lines <行數> <檔案名稱>
    # or
    $ head -n <行數> <檔案名稱>
  3. tail: 顯示檔案後面幾行的內容
    使用方法與 head 基本一致

    1
    2
    3
    4
    $ tail <檔案名稱>
    $ tail --lines <行數> <檔案名稱>
    # or
    $ tail -n <行數> <檔案名稱>
  4. less: 利用分頁模式檢視檔案內容

    1
    $ less <檔案名稱>
  5. touch: 建立檔案

    1
    $ touch <檔案名稱1>, <檔案名稱2>...
  6. ln: 建立連結(捷徑)

    1
    $ ln <目標檔案名稱> <連結的路徑>

今天就先這樣吧!希望不要嚇跑團員。