Rust以外無意味
tags: 情報
この記事はeeic (東京大学工学部電気電子・電子情報工学科) Advent Calendar 2019の11日目の記事として書かれました
Rustとは
公式HPによれば
- Performance
- Reliability
- Productivity
という長所がある言語なようです
下のように
Rust以外無意味である
— ゴッドエイムあきら@テストステ論の人 (@GodAimAkira) December 5, 2019
yukiのアドべ、rustで提出してるのおれだけ?アマゾンもマイクロソフトも投資してる言語ですよ?C++をやめろ。無意味
— ゴッドエイムあきら@テストステ論の人 (@GodAimAkira) December 7, 2019
Rust以外は無意味なのです
C++でバリバリにコードを書いたことがないとそのありがたみがわからないよ的な文章も読みました
しかし,そう言われても実際にどういうものかわからないとこれが真実かイキリかどうか見分けがつきません
ということで実際にドキュメントを読んで短いコードを書いてみることにしました
どのドキュメントを読んだのか
公式のレポジトリにあるものを読みました
の3種類があります
Nightly
(毎日更新)->Beta
(6週間でNightly
から昇格)->Stable
(6週間でBeta
から昇格)という風になっているようです
私はStable
を読みました
日本語版は2018年Editionに対応していないのでまだ読まないほうが良いと思ったので英語の方を読みました
読んだ感想
- 競プロをするだけなら1~9章と10,12,13,18章を読んで後は他人のコードを見ながらコードを書けばなんとかなりそうな気がします
- コンパイラがめちゃくちゃ賢い色々なパラダイムを含む言語だと思いました
- CやC++を書いたことがない人(メモリに対する知識がない人)がいきなりRustを書くのは大変な気がします
- バグの温床になりそうな部分を片っ端から潰している言語で使えるようになったら楽しそうです
- Rustで書いている人が強いという話は本当っぽいなぁと思いました(ただなんちゃってみたいな人は除く)
読んでとりあえずコードを書く
Rustという言語の強みはコンパイラと言いました.これは本当でコンパイラが少しでもバグの原因になりそう!というコードを見つけたら教えてくれます
ということで適当に書いてみます
フィボナッチ数
プログラミング言語の勉強をする時,最初は再帰関数の練習としてフィボナッチ数を書きますよね(?)
ということで次のような感じで0~10のフィボナッチ数は書けます
fn main() { println!("!Fibonacci!"); for i in 0..11 { println!("{}th Fibonacci number is {}", i, fibonacci(i)); } } fn fibonacci(n: u32) -> u32 { if n == 0 || n == 1 { 1 } else { fibonacci(n - 1) + fibonacci(n - 2) } }
実行するとこんな感じに出力されます
!Fibonacci! 0th Fibonacci number is 1 1th Fibonacci number is 1 2th Fibonacci number is 2 3th Fibonacci number is 3 4th Fibonacci number is 5 5th Fibonacci number is 8 6th Fibonacci number is 13 7th Fibonacci number is 21 8th Fibonacci number is 34 9th Fibonacci number is 55 10th Fibonacci number is 89
このコードを見ると
「あれ?そんなに難しくじゃん」
と思うかも知れません.しかし,後ほんの少し複雑なコードを書くと困ったことになります
Hashmapを使った問題
LeetCodeで一番解かれている問題を使います
めちゃくちゃ簡単なこの問題ですが,Rustで書くと落とし穴が何個か有ります
問題の概要はある整数列が与えられその値から2つの異なる値を足し合わせてtarget
という目的の数になること
解答は
map<target - num0, num1>
というHashMap
を作り,この値があればそれを出力し,なければ新しくkeyとvalueを新しく格納する
というものです
下のように書きました
use std::collections::HashMap; impl Solution { pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> { let mut map: HashMap<i32, i32> = HashMap::new(); let mut res: Vec<i32> = Vec::new(); for (i, num) in nums.iter().enumerate() { if (map.contains_key(&(target - num))) { res.push(map[&(target - num)]); res.push(i as i32); return res; } map.insert(*num, i as i32); } return res; } }
この短いコードの相田に以下のような点に注意する必要が有ります
map.contains_key(&(target - num))
に関して- ここでは
HashMap
の仕様上&
を付けてborrow
する必要がある(他はダメ)
- ここでは
map.insert(*num, i as i32)
に関してnum
はnums.iter().enumerate()
から取り出しており,borrow
されており,*
を付けてdereference
をしないとinsert
できないため(これはHashMap
にinsert
する際にownership
が移ることから)i as i32
はi
のままだとusize
(符号なし)というデータ型なので出力形式とマッチしないから
このように実行時のバグをなくすためにコンパイル時に指摘しまくります
自分もあまり理解しておらず理解が浅いうちはコンパイラにお世話になりっぱなしだと思います
結論
Rust以外無意味ではなくてRust(が書けないエンジニアはコンピュータを分かったつもりで書いているので)無意味ということなのかなと思いました
C++やCをわかっていない人が書いても確かに恩恵が分かりにくそうだと感じました.というのも一度メモリに触れておかないとコンパイラに頼りっぱなしでごちゃごちゃやって理解した気になってしまいそうだと感じたからです
基本大事ダネ☆
次回
C言語以外無意味
続く...