https://doc.rust-jp.rs/book-ja/ch10-00-generics.html
## ジェネリックなデータ型
- `T`は"type"の省略形
- `fn hoge<T>(list: &[T]) -> T {...}`
コンパイルエラーを自力で解決する。
```rust
fn largest<T: Copy + Ord>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
```
[[メソッド (Rust)|メソッド]]定義の場合、`impl`に`<T>`が必要。
```rust
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
```
特定の[[ジェネリックな型]]をもつ場合のみ[[メソッド (Rust)|メソッド]]が実装されるケース。
```rust
impl Point<f32> {
fn x(&self) -> &f32 {
&self.x
}
}
```
- [[ジェネリクス (Rust)|ジェネリクス]]を使ってもコードの実行は遅くならない
- [[単相化]]のおかげ
たとえば以下のコードがあるとき
```rust
let integer = Some(5);
let float = Some(5.0);
```
[[単相化]]されると以下のようになる。
```rust
// _i32 で具体化
enum Option_i32 {
Some(i32),
None,
}
// _f64 で具体化
enum Option_f64 {
Some(f64),
None,
}
fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}
```
## トレイト: 共通の振る舞いを定義する
`main.rs`
```rust
// Summaryをuseしないとtweet.summarize()がエラーになる
use trait_sandbox::{Summary, Tweet};
fn main() {
let tweet = Tweet {
username: String::from("hourse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false
};
println!("1 new tweet: {}", tweet.summarize());
}
```
`lib.rs`
```rust
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
```
- [[Rustの外部トレイトは外部の型には実装できない]] ([[コヒーレンス]])
- [[Rustの外部トレイトは内部の型に実装できる]]
- [[Rustの内部トレイトは外部の型に実装できる]]
- [[デフォルト実装]]
- [[impl Trait構文]]
- [[トレイト境界]]
- [[複数のトレイト境界を指定]]
- [[where句を使ったトレイト境界の指定方法]]
- [[Rustのimpl Trait構文でトレイトを実装している型を返す]]
> largestの別の実装方法は、関数がスライスのT値への参照を返すようにすることです。 戻り値の型をTではなく&Tに変え、それにより関数の本体を参照を返すように変更したら、 CloneやCopyトレイト境界は必要なくなり、ヒープ確保も避けられるでしょう。 これらの代替策をご自身で実装してみましょう!
できた。
```rust
extern crate core;
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list.iter() {
if item > largest {
largest = &item;
}
}
largest
}
fn main() {
let xs = vec![1, 10, 5];
let r = largest(&xs);
eprintln!("r = {:?}", r);
}
```
- [[PartialOrdトレイトとOrdトレイトの違い]]
- [[ブランケット実装]]
## ライフタイムで参照を検証する
- [[ライフタイム]]の主な目的は[[ダングリング参照]]を回避すること
```rust
fn main() {
let r;
{
let x = 5;
r = &x;
}
// rに束縛されたxの参照、xは内側のスコープで定義されているのでここでは無効に...
println!("r: {}", r);
}
```
[[ライフタイム]]を考慮した書き方。if文の分岐は実行時になるため[[コンパイラ]]は[[ライフタイム]]を推測できないが、参照`x`と`y`、および戻り値がすべて同じ[[ライフタイム]]であると保証できていれば、その長さにかかわらずこの関数は成立すると言える。
```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
```
`string1` > `string2` = `result` という[[ライフタイム]]の長さ関係があるとき、`longest`関数は問題なく動く。
```rust
fn main() {
let string1 = String::from("long string is long");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("The longest string is {}", result);
}
}
```
なぜなら、`result`より長く生きる[[参照]]は`longest`の引数に存在せず、`longest`の戻り値は引数の[[ライフタイム]]と同等になるため。(実際には`string1`と`string2`のどちらと判断されるのかは気になる...)
しかし、以下の場合は異なる。`string2`が`longest`の戻り値として返されたとき、`result`が使われるときには`string2`の[[ライフタイム]]は終了しているはず。つまり、`result`は[[ダングリング参照]]になってしまう。
```rust
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is {}", result);
}
```
言い換えると、
```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
```
というのは
- `x`と`y`の**より短いスコープが`'a`のライフタイム**となる
- `x`と`y`と戻り値のスコープの長さが同じである必要はない
を意味する。
- [[関数から参照を返す場合、戻り値型のライフタイム引数は、引数のうちどれかのライフタイム引数と一致する必要がある]]
- [[構造体のフィールドが参照型の場合は必ずライフタイム注釈が必要]]
- [[ライフタイム省略]]
- [[ライフタイム省略規則]]
[[ライフタイム]]計算の3規則
1. [[参照]]の各引数は、それぞれ独自の[[ライフタイム引数]]を得る
2. [[入力ライフタイム]]引数が1つなら...
- [[出力ライフタイム]]引数に同じ[[ライフタイム引数]]を割りあてる
3. [[入力ライフタイム]]引数が2つ以上なら...
- そのうちの1つが `&self` や `&mut self`、すなわち[[メソッド (Rust)|メソッド]]だったら
- `self`の[[ライフタイム]]を[[出力ライフタイム]]引数に割り当てる
- そうでなかったら
- 計算は不可能なので、**[[ライフタイム注釈]]を明示する必要あり**