---
# System prepended metadata

title: Rust テキスト学習 8
tags: [type, as (cast), static, Rust, const]

---

###### 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トレイト
参照外し演算子 * をオーバーロードする。
*(ポインタ変数) で 中身が見れるようになるので、参照外しという。

型強制などに有効


