やっつけな日常(34) Rustに入ればRustに従え、self.0って何?構造体とトレイト

Joseph Halfmoon

前回は、時にselfになったりSelfになったりする「ヤバイ奴」selfを少し勉強してみました。しかし、まだまだ分からないことだらけです。直ぐにCかPythonを連想してしまう年寄りには意味不明な記述をまた見つけました。self.0。なんですかこれは? 構造体の特定形式向けにトレイトを実装したら現れてきます。

今回も、「Rust By Example 日本語版」様の以下のページを参照させていただいております。

構造体

Cみたいな構造体とタプルみたいな構造体?

上記のページには構造体には3種あり、と記述されているのですが、今回試してみるのは、Cみたいな構造体、名前をもったフィールドを内部に含むものと、タプル(Pythonなどでお馴染みデス)みたいな構造体の2種類です。

作製したものは、どちらもi32型の整数を2個保持するだけのものです。意図としては、

    • newで新たな構造体インスタンスを生成し
    • is_rangeで、メソッドに渡した数が、構造体が保持する上下のリミット値の間に挟まれるときは真を返す

といったなんでもない処理です。その処理を実装するために、trait を定義しています。トレイト、Rustやるまでは聞いたこともなかったですが、他の言語における interface みたいなもん?知らんけど。

なお、structの前にオマジナイの #[derive(Debug)] が書いてあるのは、Debugを「継承」すると構造体をprintln!するときなどお楽なためです。

struct

トレイトを各構造体のために実装

上記のようにトレイトを定義しただけでは何もできないので、Oprというトレイトを実装していきます。まずは、C言語風の構造体、Clikeに対して実装してみます。Clikeのフィールドはお名前があるので、self.xyzのように書けます。このあたりはPythonなどと同じ雰囲気で、違和感ありませぬ。

なお、以前だったら return 戻り値 などと書いていたところを return 書かなくなりました。少し Rust に慣れてきた?

implClike

さて、「タプルみたいな」Tpllikeに対するOprの実装は以下です。登場しました。self.1、self.0。「タプルみたいな」構造体の場合、フィールドにお名前が無いので、0、1とかでアクセスしているのね。なあんだ。

self0EC

実験用のRustプログラムと実行

以下は、実験用のソースです。両方の構造体を生成して、働きをみるもの。

#[derive(Debug)]
struct Clike {
    abc: i32,
    xyz: i32,
}

#[derive(Debug)]
struct Tpllike(i32, i32);

trait Opr {
    fn new(mx: i32, mn: i32) -> Self;
    fn is_range(&self, dat: i32) -> bool;
}

impl Opr for Clike {
    fn new(mx: i32, mn: i32) -> Clike {
        Clike{ abc: mx, xyz: mn }
    }

    fn is_range(&self, dat: i32) -> bool {
        (self.xyz > dat) && (self.abc < dat)
    }
}

impl Opr for Tpllike {
    fn new(mx: i32, mn: i32) -> Tpllike {
        Tpllike( mx, mn )
    }

    fn is_range(&self, dat: i32) -> bool {
        (self.1 > dat) && (self.0 < dat)
    }
}

fn main() {
    println!("C_like struct and tupple.");
    let c1: Clike = Opr::new(11, 22);
    let t1: Tpllike = Opr::new(20, 33);
    println!("test 10, c1: {}", c1.is_range(10));
    println!("test 10, t1: {}", t1.is_range(10));
    println!("test 21, c1: {}", c1.is_range(21));
    println!("test 21, t1: {}", t1.is_range(21));
    println!("test 35, c1: {}", c1.is_range(35));
    println!("test 35, t1: {}", t1.is_range(35));
    println!("c1: abc={} xyz={}", c1.abc, c1.xyz);
    println!("t1: 0  ={}   1={}", t1.0, t1.1);
    println!("c1: {:?}", c1);
    println!("t1: {:?}", t1);
}

ビルドして実行してみたところが以下に。

Results

意図通りに動いているようです。知っていれば簡単だけれど、知らないでいるとなんだかな~ ビックリさせられることが多いよな、Rust。

やっつけな日常(33) Rustに入ればRustに従え、self、Self、&self へ戻る

やっつけな日常(35) Rustに入ればRustに従え、「一切メンバ無」の構造体って何よ? へ進む