💪

【Rust】北斗神拳とRustの類似性についての考察

2024/01/18に公開

はじめに

数日前にこのような記事を書きました。
https://zenn.dev/woden/articles/162af03fb87476

リンク先の記事では、Borrow checkerとライフタイムについてRustのコードの実例を挙げながら、出来るだけ分かりやすく説明しようと試みました。

実際に分かりやすかったかどうかは分からないのですが、この記事を読み返していると、ふとRustと北斗神拳には極めて高い類似性がある事を発見し、その考察について記す事で、より分かりやすい説明が出来るようになるのではないかと考えたため、改めて新しい記事として投稿してみたいと思います。

北斗神拳とは?

https://ja.wikipedia.org/wiki/北斗神拳

Wikiから重要な箇所を引用します。

一子相伝の暗殺拳であり、2000年間他門に敗れたことはないとされ、戦いの中で奥義を見出し、常に進化を続ける点から
「地上最強の拳」、「闘神の化身(インドラ・リバース)」と呼ばれている。北斗神拳の真髄は極限の怒りと哀しみであ
るといわれ、哀しみを背負う者のみが究極奥義を極められる。「北斗宗家の拳」の発展形。

最も重要なのは、一子相伝というところです。
その次に重要なのは、哀しみを背負う者のみが究極奥義を極められるというところです。

一子相伝という事は、北斗神拳を受け継ぐ事が出来るのは、ただ一人の弟子のみ、という事になります。

Rustとの類似性

察しのいい人は何となく気付き始めていると思いますが、Rustの所有権は、北斗神拳のように一子相伝で脈々と受け継がれる仕組みと完全に一致しています。

struct Hokutoshinken{
	ver:isize
}
fn main(){
	let mut syuken=Hokutoshinken{ver:1};
	let mut ryuken=syuken;
	let mut kenshiro=ryuken;

	ryuken.ver=2;	// 所有権がkenshiroに移っているのでエラーになる。Youはshock!
}

上記のコードでは、まずsyukenという変数が始祖としてあり、Hokutoshinkenという値を持っています。
それがryuken、kenshiroへと引き継がれていきます。
Hokutoshinkenを誰かに引き継ぐという事は、自身は継承者の資格を失ってしまうため、継承が済んだ後に値にアクセスしようとするとコンパイラにエラーを吐かれてしまいます。
継承後に「北斗神拳ver2.0」とかを勝手に作ろうとしても既に権利を失ってしまっているので出来ません。
この哀しみを乗り越えた先にやっとコンパイルが通り、安全にプログラムを実行する事が出来るのです。

一子相伝を扱う他の作品

北斗神拳やRustの所有権のように一子相伝で師から弟子へと継承されるという設定は、他の作品にも見る事が出来ます。

代表的なものとしては、るろうに剣心の飛天御剣流があります。
https://ja.wikipedia.org/wiki/飛天御剣流

北斗の拳についての造詣がそれほど深くなく、るろうに剣心についての方が詳しいという方の場合は、北斗神拳の代わりに飛天御剣流と読み替えてもらった方がより理解しやすいかもしれません。
当記事で伝えたい範囲に限れば、両者には完全な互換性があります。

借用と複数の弟子

北斗神拳は一子相伝というものの、継承前の修行においては複数名の弟子をとり、その中から一人だけ真の継承者を選ぶというのが慣例のようです。

この修行中の弟子という存在は、Rustの借用という仕組みとかなり類似しています。

fn main(){
	let mut ryuken = Hokutoshinken{ver:1};
	let kenshiro= &ryuken;
	let toki = &ryuken;
}

上記のコードは、ryukenという師から、kenshiroとtokiがHokutoshinkenを借用しています。
kenshiroとtokiは修行中ですので、Hokutoshinkenを自由にアレンジするような事は許されていませんが、kenshiroとtokiがそれぞれHokutoshinkenを参照する事には何の問題もありません。

可変借用とBorrow checkerと北斗神拳の真の継承者

さて、ここで可変借用という問題が出てきます。

fn main(){
	let mut ryuken=Hokutoshinken{ver:1};
	let kenshiro= &mut ryuken;
	let toki = &mut ryuken;
}

このようなコードはダメなコードです。

北斗神拳の真の継承者は一人だけである必要があるように、Rustの可変参照も一つの変数にしか持たせる事が出来ません。

ですので、そもそも真の継承者が決まっていない状態で&mutをkenshiroやtokiに与えてはいけません。そんな事をしてはkenshiroかtokiのどちらかが勝手に北斗神拳を変えてしまうかもしれません。

ですので、真の継承者を決定するまでの間は、&mutを与えるのはryukenの分身のみ、という考え方である必要があります。

そして、分身は同一スコープ内に同時に複数生む事が出来ない、という世界観設定で考えると、このあたりの仕組みは納得する事ができます。

fn main(){
	let mut ryuken=Hokutoshinken{ver:1};
	{
		let bunshin_of_ryuken= &mut ryuken;
		bunshin_of_ryuken.ver = 2;
	}
	{
		let bunshin_of_ryuken2= &mut ryuken;
		bunshin_of_ryuken2.ver = 3;
	}
}

このコードは問題なく通ります。

しかし、

fn main(){
	let mut ryuken=Hokutoshinken{ver:1};
	let kenshiro= &mut ryuken;
	{
		let bunshin_of_ryuken= &mut ryuken;
		bunshin_of_ryuken.ver = 2;
	}
	{
		let bunshin_of_ryuken2= &mut ryuken;
		bunshin_of_ryuken2.ver = 3;
	}
}

このように、kenshiroに&mutな可変参照を与えてしまっていると、世界の摂理(=Borrow checker)により、不正が検出され、エラーを発生させます。
この仕組みによって、kenshiroがHokutoshinkenを勝手に改変するような事態は事前に阻止されるのです。

北斗神拳の継承(ムーブ)

北斗神拳を継承するという事は、所有権を完全に移す必要があります。
借用するだけでは継承した事にはなりません。

let mut kenshiro= ryuken;

とする事で、kenshiroはryukenから北斗神拳を真の意味で継承する事が出来るのです。

Discussion