Rust: Fully Qualified Syntax について簡単なメモ

2021/3/31 更新

高度なトレイト - The Rust Programming Language 日本語版

を知らなかった、これを読んでください

経緯

数時間前に「僕はチンパンジーだからでパーサコンビネータ使うの難しいな〜、LR(1)パーサを手書きするのが一番早いですよ〜」と同僚と会話をしていたid:Krouton です。フルスクラッチでやる縛りを設けてないので今回実装するパーサはパーサジェネレータを使おうかなと考えていました。チンパンジーだから分からん、と逃げていても一生進まないので nom の使い方を調べていたら友人のエントリにヒットして読んでたらFully Qualified Syntaxという知らない概念に出会いました。

drumato.hatenablog.com

該当エントリ内に書いてあるとおり公式を読めば*1終わりっちゃ終わりなのですが、ググって日本語の記事がないのも寂しいのでパーサのモチベが無くならない程度に書きます。

何が嬉しいのか

impl した trait のメソッド名が他の impl と被った時にどの trait のメソッドを呼び出すのか一意に定める事ができます。

解説: selfを取る場合

そんなに難しい概念ではないので公式のソースコードをそのまま持ってきます。

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
}

fn main() {
    let person = Human;
    person.fly(); // *waving arms furiously*
    Pilot::fly(&person); // Pilot trait の fly を呼び出す
    Wizard::fly(&person); // Wizard trait の fly を呼び出す
}

personから Pilot のfly や Wizard の fly が呼び出せます。良かったですね。

余談

struct A;
trait B {
    fn xxx(&self) -> bool;
}

impl A {
    fn xxx(&self) {}
}

impl B for A {
    fn xxx(&self) -> bool {
        true
    }
}

fn main() {
    let a = A;
    // bool じゃないほうが呼ばれるのでコンパイルエラー
    if a.xxx() {
        println!("implicit");
    } else {
      println!("explicit");
    }
}

ちなみにこういう例でも implicit な呼び出しはしてくれないです。それもそうか。

解説: self を取らない場合

selfを取らない場合は

trait Animal {
    fn baby_name() -> String;
}

struct Dog;

impl Dog {
    fn baby_name() -> String {
        String::from("Spot")
    }
}

impl Animal for Dog {
    fn baby_name() -> String {
        String::from("puppy")
    }
}

fn main() {
    println!("A baby dog is called a {}", Dog::baby_name());
    // Dog からどうにかして Animal の baby_name を呼びたいので as を使う
    println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}

という風に as を使っていい感じにやります。良かったですね。 そういえばselfを取らない場合も同様に implicit なヤツはやってくれないです。頑張って書きましょう。

所感

impl Person {
}

の例ってtraitをimplしてるわけではないと思うのですがこのケースってなんで呼べばいいんだろう?