クロージャー(Golang and Rust)

現代の言語ではクロージャー機能を多くの言語で持っていますが、同じ機能(単純な1の加算)をGolangとRustで実装の比較。Rustの説明で出てくる、クロージャーは環境をキャプチャーできる匿名関数という定義はわかりやすい。

<Golang>

package main

import "fmt"

func add(i int) func() int {
	n := i

	clo := func() int {
		n++
		return n
	}

	return clo		// equivalent to specify anonymous function here and maybe it's more popular
}

func main() {
	a := add(1)
	for i := 1; i < 10; i++ {
		fmt.Println(a())
	}
}

<Rust>

fn f1(i: i32) -> Box<dyn FnMut -> i32> {	// FnMut recieves &mut self
	let mut i = i;						// dyn keyword sepcifies a trait pointer in the heap area
	Box::new(move || {				// force to allocate values in the heap area
		i += 1;
		i
	})
 }
 
 fn main() {
	 let mut cup = f1(0);
	 for _ in 1..10 {
		 println!("{}", cup());
	 }
 }

コードの参考は、

https://scrapbox.io/takker/Rustで関数を返す関数を作

FnMutの解説は、

https://qiita.com/hiratasa/items/c1735dc4c7c78b0b55e9

Fnでは変更できないし、FnOnceでは一度しか呼べないのでFnMutの指定になります。

比較してみると、Rustの方が細かな指定が必要ですが、これはメモリ管理に関する指定を明示的に行わなければいけない言語だからでしょう。したがってこれぐらいの例では変わらないけれども、コードは長めになります。比較してGolangは細かな操作はしなくとも使うだけなら簡単ということになるでしょうか。

Box<dyn … >については、

Boxは変数をスタック領域ではなくヒープ領域への割り当て、dynについては以下の通り、

https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.html

“Rust tries to be as explicit as possible whenever it allocates memory on the heap. So if your function returns a pointer-to-trait-on-heap in this way, you need to write the return type with the dynkeyword

 

admin