Rust勉強中に遭遇したことメモ - 随時更新

let if

let ifはパターンマッチングにおいて、一つだけマッチングさせたいときに使用する。

if let Some(1) = a {
	...
}

これは

match a {
	Some(1) => ...
	_ => ()
}

と等価である。

Some

someはsomething、Option型において何かあるかを示す型

let a : Option<i32> = Some(10);  
let b : Option<i32> = None;  
if let Some(10) = a {  
      
}

他言語でいうnullをこれで置き換えている。

生文字列

文字列を#r""#と書くと、その文字列が生文字列として扱われる。
例えば、パスを指定したいときなど。

let path = r#"C:\Users\user"#;

エスケープしなくともよくなる。

モジュール関係

Rustでは、モジュールを使用してimport/exportなどを行う。]
ファイル分けをするならこのようにディレクトリと同じ名前のファイルを作成して、そこからディレクトリの中のファイルをexportする。

  • src
    • application
      • aaa.rs
    • domain
      • bbb.rs
    • infrastructure
      • ccc.rs
    • presentation
      • ddd.rs
    • application.rs
    • domain.rs
    • infrastructure.rs
    • presentation.rs

例えば、application.rsの中身はこんな感じ

pub mod aaa;

pubpublicを表すアクセス修飾子

Stringと&str

Stringはメモリ領域を主体的に持っていて、そこに値の実態が格納されている
&strはその変数自体のメモリ領域に値がない(参照)、アドレスのみ
ちなみに、ただダブルクォーテーションで囲むと、&str型になるので注意

Stringの最初の文字いくつか消す

let s = String::from("1234567あいうえお");
let new_s: String = s.chars().skip(7).collect();
println!("{}", new_s);

chars()でy文字スキップしてからそのあとの文字を取得していく。この場合、日本語にも対応

オブジェクトを文字列に変換する

formatを使用すると、Stringに変換することができる

let n = format!("{:?}", obj);

map

例えば、以下のコード

content = !vec[124, 43, 65, 243];
content.iter().map(|&b| b as char).collect();

ここでmapの中身を見ていく。
まず、|&b| b as charはvecの中身を一つ取って、それをcharとしてみなしている。|&b|は参照はがしのこと

トレイトを型として扱う

例えば、以下の例。

trait Object { }
 
struct a {data: i32}
struct b {data: String}
 
impl Object for a { }
impl Object for b { }

このとき、トレイトを型として使用したい。

let vec : Vec<Object> = vec![]

しかしこれはエラーとなり、IDE場などで警告が出てしまう
これはトレイトが実行時にそのサイズを決定することができないため。
例えば上の例でいうと、aとbの構造体はそれぞれサイズが違うために、Rust上では同列に扱うことができない。
そのため、トレイトはサイズを決定することができない。実行時にどの具象型が入るかわからないためである。

そのためdynとBoxを使用する。

let vec : Vec<Box<dyn Object>> = vec![]
 
vec.push(Box::new(構造体a))

Boxはサイズを固定するもの。
dynは動的ディスパッチ、実行時に中身が決まるものを示す

データ代入時のif

Rustでは変数の代入時にifif letを使用することができる。

a = 10
let b = if a == 10 {
	"a is 10"	
} else {
	"a is not 10"
}

if let 再代入時の所有権

if let では

let a = Some(10)
 
if let Some(num) = a {
	println!("{}", num);
}
 
println!("{}", a); //エラー

これ以降に変数aを使用することはできない。
これはif let内ですでにaのメモリが移動しているからである。
この時、変数を借用として扱うにはrefキーワードを使用する、

let a = Some(10)
 
if let Some(ref num) = a {
	println!("{}", num)
}
 
println!("{}", a); //エラーにならない

Someの型について

Someは型ではない。
SomeはOption<T>型なので、変数定義の際にはOption<T>と記述する

let a: Option<String> = Some("hello");

cloneの実装

自身で作成した構造体にはcloneが実装されていない
それを実装するにはマクロを使用する

#[derive(Clone)]
struct Sample {
	pub text: String
}

文字列の前のb

Rustではこんな書き方が存在している、

let a = b"Hello";

ダブルクォーテーションの前にbを付けるものである。
これはその文字列をバイト配列として扱うためのもの

バイトスライスで部分一致を行う

バイトスライス&[u8]型で部分一致を行う場合は、window(サイズ: u8)メソッドを使用する。

if content.windows(4).any(|w| w == b"BASE") {
	//...
}

配列文字列の結合

let a = vec!["a", "b", "c"];
a.join(",");//a,b,c

文字列を逆にする

Stringである変数の文字を逆順にする場合は以下のコードを使用することができる。

let a = "hello";
 
let reversed = a.chars().rev().collect();//olleh

chars()は文字列を文字のイテレータにする。
rev()はイテレータの文字を逆にする。
collect()はイテレータをコレクション要素にする。今回はString型

文字列のn番目の文字を取得する

let text = "hello world";
 
let char_2 = text.chars().nth(2);

chars()でStringをイテレータにしてからnth()関数で取得する

&charから&strにする

let p_char = &"c";
let p_str = &p_char.encode_utf8(&mut [0; 4])

vecの最初と最後

let vector : Vec<u32> = Vec::new();
vector.push(1);
vector.push(2);
vector.push(3);
vector.push(4);
vector.push(5);
vec.first(); //1
vec.last(); //5

traitにtraitを継承

この機能はSuperTraitsといわれる

pub trait Expression {}
pub trait Operand: Expression {}
pub trait Operator: Expression {}

16進数判定

pub fn is_hex_object(token: &str) -> bool {  
    !token.is_empty() && token.chars().all(|c| c.is_ascii_hexdigit())  
}

all()メソッドは、要素をイテレートしていって、条件不一致の場合、即座にfalseを返す関数。

is_ascii_hexdigit()はRustの標準ライブラリで、高速。

配列での型チェック

let [型(ローカル変数)] = [チェックする変数] else { 型に当てはまらない場合の処理 }といった構文を使用すると、一度にif letを行うことができる。

let [  
	OperandType::Float(r),  
	OperandType::Float(g),  
	OperandType::Float(b)  
] = [  
    &buffer[0], &buffer[1], &buffer[2]  
] else {  
    return None;  
};

アクセスした配列の要素がindex外の時だけ処理を分岐する

要素がそん座視しているかどうか確認する方法として、Vec::get(index)が存在する。

let fruits = ["apple", "banana", "orange"];
 
let isExist = fruits.get(3);//indexの3は存在しないのでNoneが返される。

配列を分割する

chunksはn要素ごとのスライスを作成する。

let data = vec![1, 2, 3, 4, 5, 6];
let chunked: Vec<Vec<i32>> = data.chunks(2).map(|c| c.to_vec()).collect();
 
println("{}", chuked);
//[[1, 2], [3, 4], [5, 6]]

wasmビルド時にgetrandomがない時

このようなエラーが出た際に、

error: The wasm32-unknown-unknown targets are not supported by default; you may need to enable the "wasm_js" crate feature. For more information see: https://docs.rs/getrandom/0.4.2/#webassembly-support
   --> C:\Users\rerur\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\getrandom-0.4.2\src\backends.rs:176:17
    |
176 | /                 compile_error!(concat!(
177 | |                     "The wasm32-unknown-unknown targets are not supported by default; \
178 | |                     you may need to enable the \"wasm_js\" crate feature. \
179 | |                     For more information see: \
180 | |                     https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#webassembly-support"
181 | |                 ));
    | |__________________^
 
 
error[E0425]: cannot find function `fill_inner` in module `backends`                                       
   --> C:\Users\rerur\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\getrandom-0.4.2\src\lib.rs:120:19
    |
120 |         backends::fill_inner(dest)?;
    |                   ^^^^^^^^^^ not found in `backends`
 
 
error[E0425]: cannot find function `inner_u32` in module `backends`                                        
   --> C:\Users\rerur\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\getrandom-0.4.2\src\lib.rs:144:15
    |
144 |     backends::inner_u32()
    |               ^^^^^^^^^ not found in `backends`
    |
help: consider importing this function
    |
 18 + use crate::util::inner_u32;
    |
help: if you import `inner_u32`, refer to it directly
    |
144 -     backends::inner_u32()
144 +     inner_u32()
    |
 
 
error[E0425]: cannot find function `inner_u64` in module `backends`
   --> C:\Users\rerur\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\getrandom-0.4.2\src\lib.rs:158:15
    |
158 |     backends::inner_u64()
    |               ^^^^^^^^^ not found in `backends`
    |
help: consider importing this function
    |
 18 + use crate::util::inner_u64;
    |
help: if you import `inner_u64`, refer to it directly
    |
158 -     backends::inner_u64()
158 +     inner_u64()
    |
 
 
For more information about this error, try `rustc --explain E0425`.                                        
 
error: could not compile `getrandom` (lib) due to 4 previous errors

これはlopdfというクレートを使用している際に、lopdfがwasm用にgetrandomを実装していないためにおこる。

対策としては依存関係にgetrandomを追加する。

[dependencies]  
getrandom = { version = "0.4.2", features = ["wasm_js"] }
lopdf = "0.40.0"  
wasm-bindgen = "0.2.122"

これだけ!