LoginSignup
0
1

More than 1 year has passed since last update.

Rustでオブジェクトに関数を実装したい

Last updated at Posted at 2022-06-05

Rustでオブジェクト指向的に関数を実装する方法を自分が読みやすいようににかんたんにまとめた。
間違っている可能性が大きいので指摘をお願いします。
2022/06/07:間違っている部分が有りましたので修正しました。

オブジェクト指向経験者のためのRust入門implまでを参考にして必要以上に細かく書いている感じです。
Rustで"this is an associated function, not a method"のエラーが出たのでメソッドと関連関数について調べてみたも参考にしています。

Struct = Class のような雰囲気

pub struct Class1 { //パブリックなstructを作成
	num: i32,
	is_true: bool
}

クラスに定義される属性(変数)はstructブロックの中で書くことができる

関連関数を書くときはimpl

impl Class1 {
	pub fn new(is_true: bool, num: i32) -> Self {
		println!("You will be able to use Class1 object I will return.");
		return Class1 { //ここのreturnは省略可,Class1はSelfとすることも可能
		    num: num,
			is_true: is_true,
		}
	}
	pub fn func1(&self, num: i32){
	    println!("You called this function with number: {}", num)
    }
}

クラスを定義したとき、そのクラスのオブジェクトを作るためにnew関数が必要になることがあるだろう。
このnew関数はprintln()メソッドで説明を出力した後に渡された2つの情報numis_trueの2つを使ってClass1を返す。
このようにimplキーワードを使用してオブジェクトへ実装した関数のことを関連関数という。

-> Class1のnew関数関係を一文目から説明していく。

1. impl Class1でClass1に関数を実装できる。
implはおそらくimplementationの略であり、実装するということである。
implの後に関数を実装したい構造体(struct)を書く。

2. 実装したい関数を書く。
標準はスコープがprivateなため外部から呼び出すことが出来ないので、pubキーワードを冒頭につけ外部から呼び出せるようにする。new関数なので呼び出せないとまずいだろう。

このとき、返り値がユニット型(()で表される空のタプル-> 要するに何も返すものがない)でないので、返す値の型を宣言する必要がある。

2022/06/07,訂正
コメント欄で指摘を頂きました。C++もどきを書いてしまっていました。
間違った表記を参考にしてしまった方がいらっしゃいましたら申し訳ないです。指摘で書いていただいたコードを使用させていただきます。
@yaito3014さん、ありがとうございました。

C++では関数名(func1など)の前に返り値を書いていた(次のように)が、

class ClassName {
 public:
  int func1(int num) {
    printf("You called this function with number: %d\n", num);
    return num;
  }
};

Rustでは矢印表記の後に明記する必要がある。

		pub fn func1(&self, num: i32) -> i32 { //[-> i32]の表記で返り値の型がi32であることを宣言している
		    println!("You called this function with number: {}", num);
		    return num; //returnは省略可
	    }

3. println()マクロでnew関数実行時にコンソールへ文字出力をする

4. return Class1 で返すClass1オブジェクトを作っている。Class1クラスの関数でClass1オブジェクトを返すので、return Selfと書くこともできる。

-> オブジェクトのメソッドと関連関数

まず、関連関数とはimplキーワードでオブジェクトに対して実装された関数のことであった。
ここでこの2つの関連関数の違いを見てみよう。

	pub fn func1(&self, num: i32) -> i32 {
	    println!("You called this function with number: {}", num);
	    return num; //returnは省略可
    }
    pub fn func2(num: i32) -> i32 {
	    println!("You called this function with number: {}", num);
	    return num; //returnは省略可
    }

これら2つの関数行う処理で違う部分は、第一引数に&selfを取るか否かである。
ここで引数に&selfを取る関連関数func1を、メソッドと呼ぶ。

ここでメソッドとただの関連関数の違いは、インスタンスから呼び出すことができるか否かだ。
それぞれインスタンスから呼び出してみると、

println!("{}",cls1_instance.func1(32));
println!("{}",cls1_instance.func2(32));
26 |     println!("{}",cls1test.func2(32));
   |                            ^^^^^ this is an associated function, not a method
   |
   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: the candidate is defined in an impl for the type `Class1`
  --> src/main.rs:18:5

2つ目の関数でエラーが発生し、エラーメッセージからfunc2はメソッドでないため、インスタンスから呼び出すことが出来ないから発生したエラーだとわかる。

ただの関連関数はクラス名::関数名()のようにして呼び出すことはできるが、インスタンス.関数名()と呼び出すことは関連関数では出来ず、メソッドとして定義する必要があることに注意する必要がある。

メソッドの第一引数&self

メソッドを作るためには第一引数を&selfとしなければならなかったが、この&selfはメソッドが呼び出されたインスタンスへの参照である。
このことを確かめるため、次のコードを実行してみる。

pub struct Class1 { //パブリックなstructを作成
	num: i32,
	is_true: bool
}

impl Class1 {
	pub fn new(is_true: bool, num: i32) -> Self {
		println!("You will be able to use Class1 object I will return.");
		return Self {
		    num: num,
			is_true: is_true,
		}
	}
	pub fn func1(&self, num_arg: i32){ //返り値はユニット型になるので->などは不要
	    println!("This function was called by you with number: {}.\nAnd, The num attribute of the instance used to call this function is {}", num_arg, self.num);
    }
}
fn main(){
    let cls1test = Class1::new(true, 32); //第2引数で32を指定しているのでnum属性は32となる。
    cls1test.func1(50); //呼び出す際の引数では50を指定する。
}

You will be able to use Class1 object I will return.
This function was called by you with number: 50.
And, The num attribute of the instance used to call this function is 32

出力結果とコードからメソッドが呼び出されたインスタンス(cls1test)の参照が&selfであることがわかる。

0
1
2

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
0
1