Chapter 4: 高度なライフタイムパターン

この章の目標

この章を読み終えると、以下のことが理解できるようになります:

  • Generic Associated Types(GATs)の理論と実践
  • Lending Iterators vs Streaming Iterators
  • Async関数での高度なライフタイム管理
  • 高度なトレイト境界(trait bounds)のテクニック
  • 実世界の複雑なライフタイム問題の解決
  • なぜ高度なパターンが必要か

    基本的なライフタイムだけでは解決できない問題があります:

  • WindowsIterator: 可変参照を返すイテレータ
  • StreamingParser: 毎回異なるライフタイムでデータを返す
  • AsyncStream: 非同期データストリーム
  • Database Cursor: クエリ結果の遅延評価

これらは最新のRust機能を駆使して実現されます。

---

1. Generic Associated Types(GATs)

1.1 GATsとは何か

背景

  • Rust 1.65(2022年11月)で安定化
  • トレイトの関連型にジェネリクスを追加
  • 長年の課題(RFC 1598: 2016年)がついに解決
  • 基本的な関連型(GATs以前)

    trait Container {
        type Item;  // ← 固定された型
    
        fn get(&self) -> Option<&Self::Item>;
    }
    
    // 使用例
    impl Container for Vec<i32> {
        type Item = i32;
    
        fn get(&self) -> Option<&i32> {
            self.first()
        }
    }
    

    Generic Associated Types(GATs)

    trait Container {
        type Item<'a> where Self: 'a;  // ← ライフタイムパラメータ!
    
        fn get<'a>(&'a self) -> Option<Self::Item<'a>>;
    }
    
    // 使用例
    impl Container for Vec<i32> {
        type Item<'a> = &'a i32;
    
        fn get<'a>(&'a self) -> Option<&'a i32> {
            self.first()
        }
    }
    

    1.2 なぜGATsが必要か

    問題: Lending Iterator

    // GATs以前は表現不可能
    trait LendingIterator {
        type Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
        //       ^^                                   ^^
        //       selfのライフタイムとItemのライフタイムが連動
    }
    

    通常のIteratorとの違い

    // 標準のIterator(所有権を移動)
    trait Iterator {
        type Item;  // ライフタイムなし
    
        fn next(&mut self) -> Option<Self::Item>;
        //                         ^^^^^^^^^^^
        //                         所有された値を返す
    }
    
    // LendingIterator(借用を返す)
    trait LendingIterator {
        type Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
        //                                  ^^^^^^^^^^^
        //                                  借用を返す(selfに紐付く)
    }
    

    視覚化

    通常のIterator:
    ┌─────────────┐
    │  Iterator   │
    │  ┌────────┐ │
    │  │ items  │ │
    │  └────────┘ │
    └─────────────┘
          │
          │ next()
          ▼
       Item(所有)
    
    LendingIterator:
    ┌─────────────┐
    │  LIterator  │
    │  ┌────────┐ │
    │  │ items  │ │ ◄────┐
    │  └────────┘ │      │
    └─────────────┘      │
          │              │
          │ next()       │
          ▼              │
       &'a Item ─────────┘
       (借用)
    

    1.3 GATsの実装例

    WindowsIterator: スライディングウィンドウ

    trait LendingIterator {
        type Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
    }
    
    struct Windows<'data, T> {
        data: &'data [T],
        window_size: usize,
        position: usize,
    }
    
    impl<'data, T> Windows<'data, T> {
        fn new(data: &'data [T], window_size: usize) -> Self {
            Windows {
                data,
                window_size,
                position: 0,
            }
        }
    }
    
    impl<'data, T> LendingIterator for Windows<'data, T> {
        type Item<'a> = &'a [T] where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
            if self.position + self.window_size > self.data.len() {
                return None;
            }
    
            let window = &self.data[self.position..self.position + self.window_size];
            self.position += 1;
            Some(window)
        }
    }
    

    使用例

    fn main() {
        let data = vec![1, 2, 3, 4, 5];
        let mut windows = Windows::new(&data, 3);
    
        while let Some(window) = windows.next() {
            println!("{:?}", window);
        }
        // 出力:
        // [1, 2, 3]
        // [2, 3, 4]
        // [3, 4, 5]
    }
    

    メモリレイアウト

    data: [1, 2, 3, 4, 5]
           ↑
           └─────┬─────────┐
    Windows      │         │
    ┌───────────┬┴┬────────┴┐
    │ data: &   │ │ size: 3 │
    │ pos: 0    │ │         │
    └───────────┴─┴─────────┘
                 │
        next()   │
                 ▼
        &[1, 2, 3]  ← 'a のライフタイム
                 │
        next()   │
                 ▼
        &[2, 3, 4]  ← 新しい 'a のライフタイム
    

    1.4 高度なGATs: 複数のパラメータ

    ジェネリック型とライフタイム

    trait Database {
        type Query<'db, T>
        where
            Self: 'db,
            T: 'db;
    
        fn query<'db, T>(&'db self) -> Self::Query<'db, T>
        where
            T: Deserialize<'db>;
    }
    
    struct PostgresDB {
        conn: Connection,
    }
    
    impl Database for PostgresDB {
        type Query<'db, T> = PostgresQuery<'db, T>
        where
            Self: 'db,
            T: 'db;
    
        fn query<'db, T>(&'db self) -> PostgresQuery<'db, T>
        where
            T: Deserialize<'db>,
        {
            PostgresQuery {
                db: self,
                _marker: PhantomData,
            }
        }
    }
    
    struct PostgresQuery<'db, T> {
        db: &'db PostgresDB,
        _marker: PhantomData<T>,
    }
    

    ---

    2. Lending Iterators vs Streaming Iterators

    2.1 Lending Iteratorの深掘り

    定義と特徴

    trait LendingIterator {
        type Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
    
        // for_eachは実装できない!
        // fn for_each<F>(mut self, f: F)
        // where
        //     F: FnMut(Self::Item<'???>) -> (),  // ライフタイムが決まらない
    }
    

    制限事項

  • for_eachが書けない: 各要素のライフタイムが異なる
  • collectできない: 所有権を取れない
  • 複数の要素を同時に保持できない: ライフタイムが重なる
  • 実例: チャンク化された可変参照

    struct ChunksMut<'data, T> {
        data: &'data mut [T],
        chunk_size: usize,
    }
    
    impl<'data, T> ChunksMut<'data, T> {
        fn new(data: &'data mut [T], chunk_size: usize) -> Self {
            ChunksMut { data, chunk_size }
        }
    }
    
    impl<'data, T> LendingIterator for ChunksMut<'data, T> {
        type Item<'a> = &'a mut [T] where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
            if self.data.is_empty() {
                return None;
            }
    
            let chunk_size = self.chunk_size.min(self.data.len());
    
            // 重要: std::mem::take を使って一時的に所有権を移動
            let data = std::mem::take(&mut self.data);
            let (chunk, rest) = data.split_at_mut(chunk_size);
    
            self.data = rest;
            Some(chunk)
        }
    }
    

    使用例

    fn main() {
        let mut data = vec![1, 2, 3, 4, 5, 6];
        let mut chunks = ChunksMut::new(&mut data, 2);
    
        while let Some(chunk) = chunks.next() {
            // 各チャンクを変更可能
            chunk[0] *= 10;
            println!("{:?}", chunk);
        }
    
        println!("{:?}", data);  // [10, 2, 30, 4, 50, 6]
    }
    

    2.2 Streaming Iteratorパターン

    streaming-iteratorクレート

    trait StreamingIterator {
        type Item;
    
        fn advance(&mut self);
    
        fn get(&self) -> Option<&Self::Item>;
    
        // 便利メソッド
        fn next(&mut self) -> Option<&Self::Item> {
            self.advance();
            self.get()
        }
    }
    

    Lending Iteratorとの違い

    Lending Iterator:
    - next() が &'a mut self を取る
    - 毎回新しいライフタイム
    
    Streaming Iterator:
    - advance() と get() を分離
    - get() は &self なので複数回呼べる
    

    実装例: ウィンドウストリーミング

    struct StreamingWindows<'data, T> {
        data: &'data [T],
        window_size: usize,
        current: usize,
    }
    
    impl<'data, T> StreamingIterator for StreamingWindows<'data, T> {
        type Item = [T];
    
        fn advance(&mut self) {
            if self.current + self.window_size < self.data.len() {
                self.current += 1;
            } else {
                self.current = self.data.len();
            }
        }
    
        fn get(&self) -> Option<&[T]> {
            if self.current + self.window_size <= self.data.len() {
                Some(&self.data[self.current..self.current + self.window_size])
            } else {
                None
            }
        }
    }
    

    使用例

    use streaming_iterator::StreamingIterator;
    
    fn main() {
        let data = vec![1, 2, 3, 4, 5];
        let mut windows = StreamingWindows {
            data: &data,
            window_size: 3,
            current: 0,
        };
    
        // 現在のウィンドウに複数回アクセス可能
        while let Some(window) = windows.next() {
            println!("Current: {:?}", window);
    
            // もう一度同じウィンドウを見れる
            if let Some(same) = windows.get() {
                println!("Same: {:?}", same);
            }
    
            // for_eachも実装可能
        }
    }
    

    ---

    3. Async関数での高度なライフタイム管理

    3.1 Async Functionのライフタイム推論

    基本的なasync関数

    async fn fetch_user(id: u64) -> User {
        // 実装
        User { id, name: "Alice".to_string() }
    }
    
    // 展開後(概念):
    fn fetch_user(id: u64) -> impl Future<Output = User> {
        async move {
            User { id, name: "Alice".to_string() }
        }
    }
    

    参照を含むasync関数

    async fn process<'a>(data: &'a [u8]) -> Result<&'a str, Error> {
        // data への参照を保持したまま非同期処理
        let parsed = parse_async(data).await?;
        Ok(parsed)
    }
    
    // 展開後:
    fn process<'a>(data: &'a [u8]) -> impl Future<Output = Result<&'a str, Error>> + 'a {
        //                                                                           ^^^
        //                                                           Futureは 'a に束縛される
        async move {
            let parsed = parse_async(data).await?;
            Ok(parsed)
        }
    }
    

    3.2 AsyncStream とライフタイム

    async-streamクレート

    use async_stream::stream;
    use futures::Stream;
    
    fn range_stream(n: u32) -> impl Stream<Item = u32> {
        stream! {
            for i in 0..n {
                yield i;
            }
        }
    }
    

    参照を返すStream

    fn lending_stream<'a>(data: &'a [String]) -> impl Stream<Item = &'a str> + 'a {
        stream! {
            for s in data {
                yield s.as_str();
            }
        }
    }
    
    // 使用例
    #[tokio::main]
    async fn main() {
        let data = vec!["hello".to_string(), "world".to_string()];
        let mut s = lending_stream(&data);
    
        while let Some(item) = s.next().await {
            println!("{}", item);
        }
    }
    

    3.3 複雑なAsync Lifetimeパターン

    複数の参照と非同期処理

    use tokio::io::{AsyncRead, AsyncWrite};
    
    async fn bidirectional_copy<'a, R, W>(
        reader: &'a mut R,
        writer: &'a mut W,
    ) -> std::io::Result<(u64, u64)>
    where
        R: AsyncRead + Unpin,
        W: AsyncWrite + Unpin,
    {
        // reader と writer を並行して使用
        tokio::select! {
            result = copy_data(reader, writer) => result,
            _ = tokio::signal::ctrl_c() => {
                Ok((0, 0))
            }
        }
    }
    
    async fn copy_data<R, W>(
        reader: &mut R,
        writer: &mut W,
    ) -> std::io::Result<(u64, u64)>
    where
        R: AsyncRead + Unpin,
        W: AsyncWrite + Unpin,
    {
        // 実装省略
        Ok((0, 0))
    }
    

    AsyncトレイトとGATs

    trait AsyncDatabase {
        type Transaction<'db>: AsyncTransaction
        where
            Self: 'db;
    
        async fn begin_transaction<'db>(&'db mut self) -> Self::Transaction<'db>;
    }
    
    trait AsyncTransaction {
        async fn execute(&mut self, query: &str) -> Result<(), Error>;
        async fn commit(self) -> Result<(), Error>;
    }
    
    // 実装例
    struct PostgresDB {
        pool: Pool,
    }
    
    impl AsyncDatabase for PostgresDB {
        type Transaction<'db> = PostgresTransaction<'db>
        where
            Self: 'db;
    
        async fn begin_transaction<'db>(&'db mut self) -> PostgresTransaction<'db> {
            PostgresTransaction {
                db: self,
                queries: Vec::new(),
            }
        }
    }
    
    struct PostgresTransaction<'db> {
        db: &'db mut PostgresDB,
        queries: Vec<String>,
    }
    
    impl AsyncTransaction for PostgresTransaction<'_> {
        async fn execute(&mut self, query: &str) -> Result<(), Error> {
            self.queries.push(query.to_string());
            Ok(())
        }
    
        async fn commit(self) -> Result<(), Error> {
            // 実装
            Ok(())
        }
    }
    

    ---

    4. 高度なトレイト境界

    4.1 Higher-Ranked Trait Bounds(復習と深掘り)

    for<'a>の詳細

    // すべてのライフタイムに対して成立
    fn apply<F>(f: F)
    where
        F: for<'a> Fn(&'a str) -> &'a str,
    {
        let s = String::from("test");
        let result = f(&s);
        println!("{}", result);
    }
    

    HRTBsとGATsの組み合わせ

    trait HigherKindedIterator {
        type Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
    
        fn filter<F>(self, predicate: F) -> Filter<Self, F>
        where
            F: for<'a> FnMut(&Self::Item<'a>) -> bool,
            //  ^^^^^^^^ すべてのライフタイムで動作
            Self: Sized,
        {
            Filter {
                iter: self,
                predicate,
            }
        }
    }
    
    struct Filter<I, F> {
        iter: I,
        predicate: F,
    }
    
    impl<I, F> LendingIterator for Filter<I, F>
    where
        I: LendingIterator,
        F: for<'a> FnMut(&I::Item<'a>) -> bool,
    {
        type Item<'a> = I::Item<'a> where Self: 'a;
    
        fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
            while let Some(item) = self.iter.next() {
                if (self.predicate)(&item) {
                    return Some(item);
                }
            }
            None
        }
    }
    

    4.2 型レベルライフタイム制約

    複雑なwhere句

    trait ComplexTrait<'a, 'b>
    where
        'a: 'b,  // 'a は 'b より長生き
    {
        type Output: 'a;
    
        fn process(&'a self, data: &'b str) -> Self::Output;
    }
    
    // 実装例
    struct Processor<'data> {
        cache: &'data Cache,
    }
    
    impl<'a, 'b> ComplexTrait<'a, 'b> for Processor<'a>
    where
        'a: 'b,
    {
        type Output = ProcessedData<'a>;
    
        fn process(&'a self, data: &'b str) -> ProcessedData<'a> {
            // cache('a) と data('b) を使用
            // 'a: 'b により、cacheはdataより長生き
            ProcessedData {
                result: data,
                cache_ref: self.cache,
            }
        }
    }
    
    struct Cache;
    
    struct ProcessedData<'a> {
        result: &'a str,
        cache_ref: &'a Cache,
    }
    

    4.3 型制約の伝播

    複雑なジェネリック境界

    trait Repository {
        type Entity<'e>: Entity
        where
            Self: 'e;
    
        fn find<'e>(&'e self, id: u64) -> Option<Self::Entity<'e>>;
    }
    
    trait Entity {
        fn id(&self) -> u64;
    }
    
    // 複数のトレイトを組み合わせ
    fn process_entities<'a, R, F>(repo: &'a R, mut func: F)
    where
        R: Repository,
        F: for<'e> FnMut(R::Entity<'e>),
        //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        //  すべてのライフタイムで動作する関数
    {
        for i in 0..10 {
            if let Some(entity) = repo.find(i) {
                func(entity);
            }
        }
    }
    

    ---

    5. 実世界のケーススタディ

    5.1 データベースクエリビルダー

    設計

    trait QueryBuilder {
        type Query<'q>: Query
        where
            Self: 'q;
    
        fn select<'q>(&'q mut self, columns: &[&str]) -> Self::Query<'q>;
    }
    
    trait Query {
        fn where_clause(&mut self, condition: &str) -> &mut Self;
        fn execute(&self) -> Result<Rows, Error>;
    }
    
    struct SqlBuilder {
        connection: Connection,
    }
    
    struct SqlQuery<'builder> {
        builder: &'builder SqlBuilder,
        select_cols: Vec<String>,
        where_clauses: Vec<String>,
    }
    
    impl QueryBuilder for SqlBuilder {
        type Query<'q> = SqlQuery<'q> where Self: 'q;
    
        fn select<'q>(&'q mut self, columns: &[&str]) -> SqlQuery<'q> {
            SqlQuery {
                builder: self,
                select_cols: columns.iter().map(|s| s.to_string()).collect(),
                where_clauses: Vec::new(),
            }
        }
    }
    
    impl Query for SqlQuery<'_> {
        fn where_clause(&mut self, condition: &str) -> &mut Self {
            self.where_clauses.push(condition.to_string());
            self
        }
    
        fn execute(&self) -> Result<Rows, Error> {
            // SQL実行
            Ok(Rows { data: Vec::new() })
        }
    }
    
    // 使用例
    fn main() {
        let mut builder = SqlBuilder { connection: Connection };
    
        let rows = builder
            .select(&["id", "name"])
            .where_clause("age > 18")
            .where_clause("active = true")
            .execute()
            .unwrap();
    }
    
    struct Connection;
    struct Rows {
        data: Vec<String>,
    }
    struct Error;
    

    5.2 パーサーコンビネータ

    ゼロコピーパーサー

    trait Parser<'input> {
        type Output;
        type Error;
    
        fn parse(&self, input: &'input str) -> Result<(Self::Output, &'input str), Self::Error>;
    }
    
    // コンビネータ: map
    struct Map<P, F> {
        parser: P,
        func: F,
    }
    
    impl<'input, P, F, O> Parser<'input> for Map<P, F>
    where
        P: Parser<'input>,
        F: Fn(P::Output) -> O,
    {
        type Output = O;
        type Error = P::Error;
    
        fn parse(&self, input: &'input str) -> Result<(O, &'input str), P::Error> {
            let (output, rest) = self.parser.parse(input)?;
            Ok(((self.func)(output), rest))
        }
    }
    
    // 文字列リテラル パーサー
    struct Literal<'a> {
        expected: &'a str,
    }
    
    impl<'input, 'a> Parser<'input> for Literal<'a> {
        type Output = &'input str;
        type Error = &'static str;
    
        fn parse(&self, input: &'input str) -> Result<(&'input str, &'input str), Self::Error> {
            if input.starts_with(self.expected) {
                Ok((&input[..self.expected.len()], &input[self.expected.len()..]))
            } else {
                Err("literal not found")
            }
        }
    }
    

    5.3 非同期ストリーム処理

    実装例

    use async_trait::async_trait;
    
    #[async_trait]
    trait AsyncStream {
        type Item;
    
        async fn next(&mut self) -> Option<Self::Item>;
    }
    
    struct FileLineStream<'a> {
        reader: &'a mut tokio::io::BufReader<tokio::fs::File>,
        buffer: String,
    }
    
    #[async_trait]
    impl AsyncStream for FileLineStream<'_> {
        type Item = String;
    
        async fn next(&mut self) -> Option<String> {
            use tokio::io::AsyncBufReadExt;
    
            self.buffer.clear();
            match self.reader.read_line(&mut self.buffer).await {
                Ok(0) => None,
                Ok(_) => Some(self.buffer.clone()),
                Err(_) => None,
            }
        }
    }
    

    ---

    まとめ

    重要なポイント

  • Generic Associated Types (GATs)
- トレイトの関連型にジェネリクスを追加 - Lending Iteratorなど、以前は不可能だったパターンを実現

  • Lending vs Streaming
- Lending: 毎回異なるライフタイム - Streaming: advance/get分離パターン

  • Async Lifetimes
- Futureは自己参照構造体 - GATs + Async = 強力なデータベース抽象化

  • 高度なトレイト境界
- HRTBs: for<'a>ですべてのライフタイムに対応 - 複雑なwhere句で精密な制御

Rustライフタイムのマスタリー

ここまで学んだ内容で、Rustのライフタイムシステムを完全に理解しました:

  • Chapter 1: 形式的理解(Tofte-Talpin、Variance)
  • Chapter 2: 複雑なパターン(複数ライフタイム、省略規則)
  • Chapter 3: 自己参照構造体(Pin、Future)
  • Chapter 4: 最先端パターン(GATs、Async)
  • これで、どんなライフタイム問題も解決できるスキルを身につけました。

    次のステップ

    実践的なプロジェクトでこれらの知識を活用しましょう:

  • 自作データベースライブラリ
  • パーサーコンビネータライブラリ
  • 非同期フレームワーク
  • Rustコンパイラへの貢献

ライフタイムは、Rustの最も強力な機能です。この知識を武器に、安全で高速なソフトウェアを構築してください。