###### tags: `Rust` `const` `static` `type` `as (cast)`
# Rust テキスト学習 8
# const と inline
## const
定数を定義する。
constはライフタイムすべてで使える
ただし、メモリ上にリソースがアロケートされることはなく
インラインで値が書き換わるので効率的。
## static
staticはグローバル変数とも呼ばれる。
インライン化は行われない。
メモリ上に固定の位置を持ち、ただ1つのインスタンスのみが存在する。
プログラム全体でライフタイムが続く
'static ライフタイムという
## static mut
mutableなstatic変数を用意する。
static mutな変数へのアクセスは unsafe な操作であり、
unsafe ブロックで行う必要がある。
```rust=
const c: i32 = 5;
static stv: i32 = 10;
static mut stmutv = 100;
unsafe {
stmutv += 10;
println!("{}", stmutv);
}
```
大抵の場合は、static と const のどちらかを選べるときは
constを使ったほうが最適化できる。
クレート全体で同じ値を使い回すときも、constのほうが良い。
# type エイリアス
type キーワード
もともとある型に別名をつける
```rust=
type Alias = String;
let a: Alias = "hello".to_string();
```
# 型のキャスト
2種類ある
- as : 安全なキャスト
- transmute : 危険なキャスト(任意)
## 型強制
type coercion = 型強制
あるデータから他のデータ型への自動的な、または暗黙的な変換
型強制と型変換はよく似ている
- 型強制 : 暗黙的
- 型変換 : 暗黙的 or 明示的
## Deref
カスタマイズ型強制を定義するトレイト
## as
明示的で安全なキャスト
いくつかルールが有る
- i/u は符号付き、なしで挙動が変わる
- f > i/u へのキャストは、0方向への丸めを行う
- f64 > f32 へのキャストは最も近い値が作られる(精度が落ちる)
```rust=
let x: i32 = 5;
let y = x as i64;
// ポインタキャスト
let a = 300 as *const char;
let b = a as u32;
```
## transmute
as キャストだと以下のコードはエラー
```rust=
let a = [0u8,0u8,0u8,0u8];
let b = a as u32;
```
4byteの0で埋められた配列を u32に変換する。
という行為は、危険なキャストである。
配列という型を異なる型であるu32として扱おうとしているため。
std::mem にある transmute モジュールを使うことで、変換できる。
当然、unsafe ブロックで包まないと成功しない。
使う人間任せの自己責任なコード。
```rust=
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
}
```
# 関連型
Rustの型システムの強力な部分
複数の型をグループ化する
## Graph の例
Node と Edge の2つのstructを使う Graphトレイト
ジェネリクス\<N, E> を使って下記のようにトレイトを書く
```rust=
trait Graph<N, E> {
fn has_edge(&self, &N, &N) -> bool;
fn edges(&self, &N) -> Vec<E>;
// etc
}
```
このようなトレイトを定義すると、このトレイトを実装する方を引数とするメソッドを書くとき、
ジェネリクスパラメータの記述が長くなる。
```rust=
fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }
```
## 関連型の定義
trait ブロックの中に、使うジェネリック型を type 演算子で定義。
そして、メソッド内で type で定義したジェネリック型を使うだけ。
関連型を使うとこのようにかけ。
```rust=
trait Graph {
type N: fmt::Display; // トレイト境界もつけられる
type E;
fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
// etc
}
```
## 関連型を使用しているトレイトの実装
implブロックでは、メソッドの実装に加えて、
type キーワード での型エイリアスの定義を用いて、
ジェネリックパラメータを実際の型に置き換える。
```rust=
struct Node;
struct Edge;
struct MyGraph;
impl Graph for MyGraph {
type N = Node;
type E = Edge;
fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
true
}
fn edges(&self, n: &Node) -> Vec<Edge> {
Vec::new()
}
}
```
# 演算子オーバーロード
std::ops; クレートにあるトレイトを使って、
構造体に +-/*% などの演算子を使ったときの振る舞いを実装できる
## Addトレイト
```rust=
pub trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
```
let z = x + y; という式があったとき、
- x = Self
- y = RHS(ジェネリックパラメータ)
- z = Self::Output
- + = 左右を引数に取る add() メソッド
の型になる。
Outputは関連型なので、 impl ブロックで型を定義する。
## Derefトレイト
参照外し演算子 * をオーバーロードする。
*(ポインタ変数) で 中身が見れるようになるので、参照外しという。
型強制などに有効