今天要繼續上一篇還未完成的資料型態,相信今天也是充實的一天那就讓我們開始吧!
Compound types 可以把很多的值合併再一起變成一個型態。Rust 有兩個主要的 compound types 分別是 tuples 以及 arrays.
tuple 是一般常用來組合型態的方法他可以自己定義不同的資料類型放在裡面,這邊要注意的是 tuple 一但宣告之後就不能對他做任何的增減項目的調整。
這邊我們直接來新增一個 tuple
fn compound_types() {
// 組合不同的型態成為一個單元
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
那麼我們該怎用取得裡面的值呢?Rust 提供一種類似 javascript 解構賦值的方法,範例如下
fn compound_types() {
// 組合不同的型態成為一個單元
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解構
let (x, y, z) = tup;
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
println!("The value of z is: {}", z);
}
另外也可以用 index 的方式拿到這個值
fn compound_types() {
// 組合不同的型態成為一個單元
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解構
println!("The value of tup.0 is: {}", tup.0);
println!("The value of tup.1 is: {}", tup.1);
println!("The value of tup.2 is: {}", tup.2);
}
那麼只是按照官網範例總是不夠的,我們來玩玩看 tuple 跟之前變數的各種不同宣告方式結合會發生什麼事情。
const GLOBAL_VALUE: &str = "發大財";
static CHANGABLE_GLOBAL_VALUE: f64 = 10.5;
fn tuple_with_mixed_data_type() {
let tup: (&str, f64, u8) = (GLOBAL_VALUE, CHANGABLE_GLOBAL_VALUE, 1);
// 解構
println!("The value of tup.0 is: {}", tup.0); // 發大財
println!("The value of tup.1 is: {}", tup.1); // 10.5
println!("The value of tup.2 is: {}", tup.2); // 1
}
看來沒什麼問題,通過。
const GLOBAL_VALUE: &str = "發大財";
static mut CHANGABLE_GLOBAL_VALUE: f64 = 10.5;
fn tuple_with_mixed_data_type() {
let tup: (&str, f64, u8) = (GLOBAL_VALUE, CHANGABLE_GLOBAL_VALUE, 1);
^^^^^^^^^^^^^^^^^^^^^^ use of mutable static
}
發現錯誤了原來 tuple 不能把 mutable 跟 immutable 組合在一起。
const GLOBAL_VALUE: &str = "發大財";
static CHANGABLE_GLOBAL_VALUE: f64 = 10.5;
fn tuple_with_mixed_data_type() {
let tup: (&str, f64, u8) = (GLOBAL_VALUE, CHANGABLE_GLOBAL_VALUE, 1);
let tup = ("挖石油", 22.0, 92);
// 解構
println!("The value of tup.0 is: {}", tup.0); // 挖石油
println!("The value of tup.1 is: {}", tup.1); // 22
println!("The value of tup.2 is: {}", tup.2); // 92
}
Shadowing 也是沒問題的。
const GLOBAL_VALUE: &str = "發大財";
static CHANGABLE_GLOBAL_VALUE: f64 = 10.5;
pub fn tuple_with_mixed_data_type() {
let mut tup: (&str, f64, u8) = (GLOBAL_VALUE, CHANGABLE_GLOBAL_VALUE, 1);
tup.1 = 22.5;
// 解構
println!("The value of tup.0 is: {}", tup.0);
println!("The value of tup.1 is: {}", tup.1);
println!("The value of tup.2 is: {}", tup.2);
}
mutable 的 tuple 就可以改變裡面任一的值。
Rust 的 array 裡面的 item 型態必須都一樣,因此不像 javascript 要在裡面放什麼都可以。
fn compound_types() {
// 陣列裡的物件必須都為同樣的類型
let months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
}
同時也提供另外一種宣告更簡短的方式,
fn compound_types() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
}
i32 是 array 物件的類型 5 則代表 array 的容量。
fn compound_types() {
let a = [3; 5];
// 等同於 let a = [3, 3, 3, 3, 3];
}
取得 array 物件的方式跟其他語言大同小異。
fn compound_types() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
let third = a[10];
^^^^^ index out of bounds
}
Note:若 index 如果超出 array 長度時在編譯時會直接報錯。
fn compound_types() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
let index = 5;
let third = a[index];
}
但若是在執行期間才發生超過範圍的情況雖然編譯會過但是會在執行到這行的時候會直接中斷程式(官方稱為 panic),這是 Rust 確保不會有任何 invalid memory 可以被存取。
接著我們來試試看可不可以改變 array 裡面的值,
fn compound_types() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
a[0] = 5;
^^^^^^^^ cannot assign
}
同樣的如果是 immutable 的 array 也是不能修改他的值。
fn compound_types() {
let mut a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
a[0] = 5;
}
若是 mutable 的則沒有問題。
今天把所有基礎的資料型態都介紹完了下一篇我們會介紹 Rust 的函式(function)。Rust 基本上也是非常適合 functional programming 的至少我用到目前為止還沒有看到太多物件導向的東西所以習慣寫 js + ReactJS 的同學應該也可以適應的很快,另外筆者我是偏好寫 FP 所以後面的例子基本上能不用物件導向就會盡量不用。
tuple 不能有 mut 的型態最大的問題其實不在 tuple ,而是直接使用到了可變的 static 的這件事,因為 Rust 中不管是讀還是寫 static mut
都是 unsafe 的 playground link ,可以試試,把 drop 包進 unsafe
中就正常了