Rustは型に厳格といいつつ「意外と融通を利かせて」くれるような気が(個人の感想っす。)それはコンパイラが厳格に管理している(変なことはできない)ために可能な技?なのかもしれませぬが。今回は「融通が利く」println!と「融通が利かない」assert_eq!を比べながら実験してみたいと思います。どちらもマクロだね。
※「やっつけな日常」投稿順 Index はこちら
※今回参照させていただいとります Rust のドキュメントは以下あたりです。
実験に使用したソース全文と実行結果
短いので先にソース全文掲げておきます。
fn main() { let s = 111; let sr = &s; let sb = Box::new(111); let sr2 = &s; let sr3 = &111; println!("s : {}", s); println!("sr: {}", sr); println!("sb: {}", sb); println!("sr2: {}", sr2); println!("sr3: {}", sr3); let ssum = s + sr + *sb; println!("ssum: {}", ssum); assert_eq!(111, s, "111 != s"); // assert_eq!(111, sr, "111 != &s"); assert_eq!(&111, sr, "&111 != &s"); // assert_eq!(111, sb, "111 != sb"); assert_eq!(Box::new(111), sb, "Box(111) != sb"); assert!(std::ptr::eq(sr, sr2)); assert!(std::ptr::eq(sr3, sr2), "ERROR!"); }
そして上記を実行したものが以下に。末尾のassert!がコケているので最後にパニックが起こってますが、それ以前は正常に通過しとります。
実験結果の吟味
最初に、整数値111を値として持つ5個の変数を定義してます。sは単純なi32型の変数。srはsの参照。sbはヒープ上のBox内に111を詰めたもの。sr2はもう1個のsの参照。sr3はsでなく整数111の参照とな。
let s = 111; let sr = &s; let sb = Box::new(111); let sr2 = &s; let sr3 = &111;
年寄の心に染みついている C であれば、*ptr と書くべきところに ptr などと書いてしまったらダメダメな結果になるにきまっているのです。しかし、太っ腹で融通が利く Rust のprintln!マクロでは、以下のような異なる変数でも、みな 111 だたと印字してくれるのでした。
println!("s : {}", s); println!("sr: {}", sr); println!("sb: {}", sb); println!("sr2: {}", sr2); println!("sr3: {}", sr3);
便利っちゃ便利だけれども、年寄はチト落ち着きませぬ。
さらにいうと、上記の変数のうち、sとsrとsbの値を足し算しようとするとこんな感じに書けます。
let ssum = s + sr + *sb; println!("ssum: {}", ssum);
単純変数 s と参照 sr はそのまま足し合わせ可能。しかしBoxに入れてある sb についてはデリファレンス * して値を取り出せばOKっと。
C頭の年寄には、この辺の挙動がなれませぬな。
println!に比べると「厳格に」比較を行ってくれるassert_eq!マクロにお願いすると差が見えてきます。
assert_eq!(111, s, "111 != s"); // assert_eq!(111, sr, "111 != &s"); // assert_eq!(111, sb, "111 != sb");
上記の最初の行は単純変数 s を数値 111 に比べて成功するのですが、2行目と3行目はコンパイルが通りません。srはリファレンスだし、sbはBox型なのでダメだと拒絶されます。println! じゃ、どちらも 111 だと印字してくれるのに。
Box型は同じ値を含むBox型と比べてやれば比較一致します。
assert_eq!(Box::new(111), sb, "Box(111) != sb");
リファレンスは、Rawポインタ同士、同じ実体数値を指していれば比較成功します。
assert!(std::ptr::eq(sr, sr2));
リファレンスの比較では、当然ですが、等価な数値を指していても異なるRawポインタの比較であれば、不成功となります。エラー、パニック。
assert!(std::ptr::eq(sr3, sr2), "ERROR!");
C頭で忘却力の年寄は頭の切り替えが追い付かない??