###### tags: `Rust` `impl` `Generic` `Some(T)` `Reslt<T, E>` `Option<T>`
# Rust テキスト学習 4
[TOC]
structに対し、関数を呼びたいとき、
baz(bar(foo)) だが、実際呼ばれる順序は foo > bar > baz
メソッド構文を使えば、foo.bar().baz();
# impl
implブロック : 定義したstructにメソッドを定義するブロック
```rust=
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
// メソッドの第一引数は特殊、self, &self, &mut self の3種類がある。
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
```
Circle構造体にarea() 面積を返すメソッドを追加
## impl メソッドの第一引数
self : 所有権の移動
&self : imutableな参照の借用(一番オススメ)
&mut self : mutableな参照の借用
呼び出す側の引数では、 foo.bar() のfooに該当する。
()内にオブジェクトを書く必要はない。
(C などのオブジェクト指向が言語レベルでサポートされない場合はそういう書き方をする)
## メソッドチェーン
foo.bar().baz() のように、メソッドを連続で実行したい。
これは、bar()で .baz()メソッドを持つオブジェクトを作成して返すことで実現できる。
```rust=
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
fn grow(&self, increment: f64) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius + increment }
}
}
let c = Circle{1.0, 2.0, 3.0};
let grow_c = c.grow(1.0).grow(2.0).grow(3.0);
```
circle.grow() メソッドは、 **半径を引数分だけ増加したCircle** を生成して返すメソッド
単に、Circle structを戻り値とするだけ
## 関連引数(Class method)
selfを引数に取らない関数。
呼び出すときは Struct::method という形になる。
Rustではよくあるパターンで、 new() などは関連メソッドであることが多い
構造体ごとにネームスペースを区切れるので同じnewというメソッド名が使える
## Builderパターン
Rustメソッドには
- methodのオーバーロード(多重定義)
- 名前付き引数
- 可変個引数
がない
構造体を作成するとき、特定の値だけ設定して残りはデフォルトの値にしたい。
こういった要望を実現するのに、Builderパターンを使う
- StructBuilder構造体(Structと同じデータ構造)
- .new() : デフォルト値で作成する
- .property(&mut self, arg)->StructBuilder : プロパティ名のメソッド。&mut selfを渡してselfを変更する
変更したい初期propertyの数だけ用意する
StructBuilderを返し、メソッドチェーンでさらなる変更 or finalizeができる
- .finalize(&self)->Struct : 設定した初期化内容を元に、structを作成して返す。
例.
```rust=
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
```
# Vector
動的な配列
Vec\<T>として提供される。
Tはどんな型でも使える
vec! マクロで作成できる。
()でも[]でも使える。(println!マクロでも同様)
[]で配列の要素にアクセスできるが、指定するインデックスはusize型でないとエラーになる・
```rust=
let v = vec![1,2,3,4,5];
v[1];
let i: usize = 0;
let j: i32 = 0;
v[i];
v[j]; //error
```
## イテレーティング
v, &v, &mut v の形でfor in 文でイテレーションできる
その他多くの便利メソッドはAPIドキュメントから
# 文字列
2種類
- &str : 文字列スライス
- String : ヒープアロケートの動的配列。
文字列リテラルは &'static str 型
## 相互変換
&str > String
&str.to_string() = &str を String に変換
String::from(&str) = &strを元にStringを作成
String > &str
&*string
## 運用面
Stringを使うと、メモリアロケーションが発生するので
必要がないならやらないほうがいい。
## インデクシング
文字列はUTF-8でエンコードされており、複数バイト対応があるため
n番目の文字を探すのは高コストな演算
よって[n]を使ったインデクシングをサポートしていない。
文字列のn番目を見るには、まず
- バイト配列、char配列のシーケンスに変換(.as_bytes() or .chars())
- .nth(n) メソッドで取得。
```rust=
let dog = hachiko.chars().nth(1);
```
charsリストの上から走査
## 連結
String + &str : 可能
String + String : 片方に & をつけて &strに型強制する。
# ジェネリクス
複数の型に対応した関数やデータ型を作成するもの
parametric polymorphism とも呼ばれる
(与えたパラメータによって、異なる振る舞いを持つこと)
## 例 Option\<T>, Result\<T, E>
Rustがstdで提供しているenum型
Option 型 = 取得できないかもしれない値の変数型。
- Some(T) : 取得できた場合の値(要素1タプル構造体)。取得するにはパターンマッチでlet Some(変数)に入れる
- None : 取得できないとき
```rust=
enum Option<T> {
Some(T),
None,
}
```
Result 型 = 処理が成功したか失敗したかという結果に使える型
- Ok(T) : 処理が成功したときの値
- Err(E) : Errorのときの値(エラーメッセージ(str) とか エラーコード(i32)とか)
```rust=
enum Result<T, E> {
Ok(T),
Err(E),
}
```
ジェネリックの第一ジェネリックパラメータは慣例的にTである
二個目以降は気にしない(Resultの場合はE)
これらのenum型のバリアントは、単なる1要素タプル構造体であり、
特別な実装などはない(と思われる)
## ジェネリック関数
```rust=
fn takes_anything<T>(x: T){ ... }
```
Tに対してジェネリック
引数にどのような方も取ることができる。
## ジェネリックStruct
```rust=
struct Point<T> {
x: T,
y: T,
}
```
Tに対してジェネリック。要するに、関数名orStruct名の横に
\<>で囲ってジェネリックパラメータを指定すると
ブロック内で型をジェネリックパラメータで置き換えることができるということである。
implブロックでも、同様に型引数を宣言する。
```rust=
impl<T> Point<T> {
fn swap(&mut self) {
std::mem::swap(&mut self.x, &mut self.y);
}
}
```
## ジェネリックの用途
幅広い
Option\<T>, Result\<T>, Vec\<T>など
汎用的にどの方でも使える方を作れる