Rust入門
🦀🦀🦀
配列
rustlet arr = [1, 2, 3];
let arr2: [&str; 3] = ["a", "b", "c"]; // `[type, size]`で配列の型を指定できる
let arr3 = ["hello"; 5]; // ["hello", "hello", "hello", "hello", "hello"]
arr2[1]; // "b"
// スライス
&arr2[1..2]; // ["b"]
&arr3[3..]; // ["hello", "hello"]
&arr3[3..3]; // []
&arr3[3..=3]; // ["hello"]
Vec
rustlet mut vec = Vec::new();
vec.push("hello");
vec.push("world");
println!("{:?}", vec); // ["hello", "world"]
let vec = vec![1, 2, 3]; // Vec<i32>
println!("{:?}", vec); // [1, 2, 3]
// スライス
println!("{:?}", &vec[1..2]); // [2]
Tuple
rustprintln!("{:?}", ()); // 空のタプル
let tuple = (1, "hello", 5.3);
println!("{}", tuple.0); // 1
println!("{}", tuple.1); // hello
println!("{}", tuple.2); // 5.3
let (n, s, f) = tuple;
println!("{}, {}, {}", n, s, f); // 1, hello, 5.3
HashMap
hashmap.rsuse std::collections::HashMap;
fn main() {
let mut h = HashMap::new();
h.insert("hoge", 1);
h.insert("piyo", 3);
h.insert("piyo", 4);
// []でキーに紐づく値を取得できる. キーが存在しないときはエラーが発生する.
println!("{}", h["hoge"]); // 1
// get()は[]とは異なり、キーが存在しなくてもエラーが発生しない
match h.get("piyo") { // 4
Some(n) => println!("{}", n),
None => println!("😫"),
}
}
HashSet
内部的には HashMap
を使用して実装されているようです
順序を維持したいときは、 HashSet
の代わりに BTreeSet
を使う
hashset.rsuse std::collections::HashSet;
fn main() {
let mut s = HashSet::new();
s.insert("hoge");
s.insert("piyo");
s.insert("fuga");
s.insert("piyo");
println!("{}", s.len()); // 3
println!("{}", s.contains("hoge")); // true
println!("{}", s.contains("piyopiyo")); // false
}
Iterator
.iter()
と .into_iter()
の違いはmoveの有無. .into_iter()
はmoveが発生するので、もとのコレクションは使用できなくなる
文字列
rustlet s = "Hello, world!"; // &'static str
let s = String::from(s); // String
タプル構造体
ruststruct Point(i32, i32);
fn main() {
let p = Point(1, 3);
println!("({}, {})", p.0, p.1); // (1, 3)
}
名前付き構造体
ruststruct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point{ x: 1, y: 3 };
println!("({}, {})", p.x, p.y); // (1, 3)
let (x, y) = (3, 5);
let p = Point{ x, y };
println!("({}, {})", p.x, p.y); // (3, 5)
// デストラクチャリング
let Point { x, y } = p;
println!("({}, {})", x, y); // (3, 5)
}
enum
rustenum Status {
OK,
Error(String),
}
fn main() {
let s = Status::Error(String::from("😑😑😑"));
match s { // Error: 😑😑😑
Status::OK => println!("OK😊"),
Status::Error(msg) => println!("Error: {}", msg),
}
}
match
rust match 10 { // => piyo 10
1 => println!("hoge"),
n @ 10 => println!("piyo {}", n),
_ => println!("fuga"),
}
ループ
rustlet mut i = 0;
while i < 3 {
println!("{}", i); // 0, 1, 2
i += 1;
}
loop {
do_something();
if some_condition_met() {
break;
}
}
for n in 0..5 {
println!("{}", n); // 0, 1, 2, 3, 4
}
メソッド
methods.rs#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
// 静的メソッド
fn new(name: String, age: u32) -> Self {
Self { name, age }
}
// 通常のメソッド
fn rename(&mut self, new_name: String) {
self.name = new_name;
}
}
fn main() {
let mut p = Person::new(String::from("hoge"), 30);
p.rename(String::from("piyo"));
println!("{:?}", p); // Person { name: "piyo", age: 30 }
}
Option
option.rsfn second(vec: Vec<i32>) -> Option<i32> {
if vec.len() < 2 {
None
} else {
Some(vec[1])
}
}
fn main() {
match second(vec![1, 2, 3]) { // => 2
Some(n) => println!("{}", n),
None => println!("None"),
}
match second(vec![1]) { // => None
Some(n) => println!("{}", n),
None => println!("None"),
}
}
lambda
rust // 引数なし
let f = || println!("Hello");
f();
// 引数あり
let add = |a: i32, b: i32| {
// ブロック
let result = a + b;
result
};
println!("{}", add(1, 2));
// closure
{
let message = "Hello world!";
let do_something = || println!("{}", message);
do_something();
}
ライフタイム
Copyトレイト
Copyトレイトを実装した型はスタック上に確保される
関数に渡す際は常にコピーされる
所有権について心配する必要はない
Cloneトレイト
.clone()
でクローンできる
AsRefトレイト
ある型から別の型への参照を取得したいときに使う
例えば、 AsRef
を使うと、以下のように &str
と String
の両方を受け取れる関数を定義できる
rustfn decorate_text<T>(x: T) -> String
where
T: AsRef<str> + Display,
{
format!("**{}**", x)
}
fn main() {
println!("{}", decorate_text("Hello"));
println!("{}", decorate_text("world".to_string()));
}
From<T>/Into<T>トレイト
Cowトレイト
Rc
参照カウントを使用したスマートポインタ
Arc
は Rc
のatomic版
Box
Box
トレイトと dyn
について
Channel
std::sync::mpsc::channel
で作成できる
参考