LoginSignup
4
2

More than 3 years have passed since last update.

Rustでクラス拡張を調べた

Posted at

概要

SwiftやKotlinなどにあるクラス拡張をRustではどうやるのか気になり調べてみました。

例えば自身の2倍を返却する関数をIntに追加したい場合などはSwiftであればこうなるかと思います。

Swift

extension Int {
    func double() -> Int {
        return self * 2
    }
}

print(5.double())

Rustで試す

Rustの場合はtraitで実装するようです。先ほどの2倍の例だとこんな感じでしょうか。


trait DoubleExt {
    fn double(self) -> Self;
}

impl DoubleExt for i32 {
    fn double(self) -> Self { self * 2 }
}

fn main() {
    println!("{}", 5.double());
}

Genericにしてみる

上の例だとi32だけでしたが、Genericにする方法を調べてみました。


mod foo {
    pub trait DoubleExt {
        fn double(self) -> Self;
    }

    use std::ops::Add;
    impl<T> DoubleExt for T where T: Add<Output = T> + Copy
    {
        fn double(self) -> T { self + self }
    }
}

fn main() {
    use foo::DoubleExt;

    println!("{}", 1.1.double());
    println!("{}", 2.double());
}

パッと見で理解し辛いので、一つづつ噛み砕いてみます。

Add Trait


use std::ops::Add;

+演算子に関するtraitをとりこんでいます。
2倍の算出をimplの中でself+selfで実装しているのでこちらが必要になります。

traitの実装


impl<T> DoubleExt for T where T: Add<Output = T> + Copy

T型にDoubleExtの実装をするところですね。
whereを使ったtrait境界の指定ではT: Add<Output = T>としています。
まずはstd::opts::Addの定義を見てみましょう。

pub trait Add<Rhs = Self> {
    type Output;
    fn add(self, rhs: Rhs) -> Self::Output;
}

上記のようにOutputが関連型となっているので、T: Add<Output = T>で実装側でOutputの型を決める必要があるということでしょうか。

Copy Trait

T: Add\<Output = T\> + Copy+ Copyの部分ですね
std::opts::Addの定義をさきほど確認しましたが、addメソッドは引数の値の所有権をそのままとるようになっています。
self + selfでは左側の値をaddに渡す時点で所有権が移ってしまうので、selfを右側の値に指定する時点では使えなくなってしまうようです。
そのためTがCopy Traitを実装していることを担保してあげる必要があるようです。

さいごに

ZEROBILLBANKでは一緒に働く仲間を募集中です。
ZEROBILLBANK JAPAN Inc.

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2