前回までのあらすじ
環境構築して、Rustが着丼した。まずはHelloWorldから……ポポーイ!!!!!!!!
今回は基本的な構文を確認して、何問かA問題を提出したい。
おためし
fn main() { let a = 10; let mut b = 11; println!("uhoho {}", a); println!("uhouho {}", b); b += 5; println!("hohoho {}", b); }
PythonというよりかはScalaに近いなぁという印象。 letがimmutableなのはいいね。ただprintln!なのが良く言えば新鮮。
fn main() { let x: i64 = 0; { let x = x + 10; println!("x: {}", x); // 10 } println!("x: {}", x); // 0 }
はえ~~~おもしろい。シャドーイングっていうらしい。 let mutっぽい挙動だけど、内部的には新しい変数を作っているのね。
fn main() { let test: u32 = "123".parse().unwrap(); println!("{}", test) }
parse()の戻り値はResultっていうScalaで言うところのOptionみたいなやつ。 getはunwrapっていうメソッド、getOrElseはunwrap_orっていうメソッドでやる。
(というかrustはsnake caseなのか)
型は色々あるけれど、i(num)とu(num)があって、uはunsignedって意味みたい。JVM系の言語じゃ見かけないと思うけど、Kotlinとかにはあるのか?
fn main() { println!("{}", 1 / 2); // 1 println!("{}", 1.0 / 2); // err! println!("{}", 1.0 / 2.0); // 0.5 }
これは意外だ。intをfloatに暗黙に変換してくれるもんだと思っていたけど、演算の際は同じ型じゃないと怒られるみたい。
fn main() { let a: [i32; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("{}", a); // err! println!("{:?}", a); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] println!("{}", a.map(|v| v.to_string()).join(" ")); // 1 2 3 4 5 6 7 8 9 10 }
Scalaだと無名関数(であってるっけ)はv => v.toString()
みたいな書き方をするが、Rustは|v| v.to_string()
と書く。なるほどね。
fn main() { let a: Vec<i32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("{:?}", a); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] println!("{}", a.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(" ")); // 1 2 3 4 5 6 7 8 9 10 }
なんだこれ!?まぁjoinが使える条件は(おそらく)Stringの配列関連で、collectの際に型を明示的に指定する必要があるっぽい。しかも型パラメータの指定がhoge[T]とかhoge
他ifやらfor/whileやらを使ってみたけど、これらはpythonっぽい。while Trueじゃなくてloopっていう制御文があるのはびっくりしたが。
その他
Atcoderのジャッジで使えるライブラリは全部突っ込むことにした。Cargo.tomlのdependenciesに以下を突っ込むだけ。
ac-library-rs = "0.1.1" once_cell = "1.18.0" static_assertions = "1.1.0" varisat = "0.2.2" memoise = "0.3.2" argio = "0.2.0" bitvec = "1.0.1" counter = "0.5.7" hashbag = "0.1.11" pathfinding = "4.3.0" recur-fn = "2.2.0" indexing = "0.4.1" amplify = "3.14.2" amplify_derive = "2.11.3" amplify_num = "0.4.1" easy-ext = "1.0.1" multimap = "0.9.0" btreemultimap = "0.1.1" bstr = "1.6.0" az = "1.2.1" glidesort = "0.1.2" tap = "1.0.1" omniswap = "0.1.0" multiversion = "0.7.2" num = "0.4.1" num-bigint = "0.4.3" num-complex = "0.4.3" num-integer = "0.1.45" num-iter = "0.1.43" num-rational = "0.4.1" num-traits = "0.2.15" num-derive = "0.4.0" ndarray = "0.15.6" nalgebra = "0.32.3" alga = "0.9.3" libm = "0.2.7" rand = "0.8.5" getrandom = "0.2.10" rand_chacha = "0.3.1" rand_core = "0.6.4" rand_hc = "0.3.2" rand_pcg = "0.3.1" rand_distr = "0.4.3" petgraph = "0.6.3" indexmap = "2.0.0" regex = "1.9.1" lazy_static = "1.4.0" ordered-float = "3.7.0" ascii = "1.1.0" permutohedron = "0.2.4" superslice = "1.0.0" itertools = "0.11.0" itertools-num = "0.1.3" maplit = "1.0.2" either = "1.8.1" im-rc = "15.1.0" fixedbitset = "0.4.2" bitset-fixed = "0.1.0" proconio = "0.4.5" text_io = "0.1.12" rustc-hash = "1.1.0" smallvec = "1.11.0"
実践編
ABC334A
単なるif文の確認。inputにproconioっていうマクロ?を使わなきゃいけないっぽい。 でもinput楽チンでいいね。
ABC333A
for文と出力の調整。vectorを文字列に変換する操作、もう少しスマートにできないかなぁ。
ABC333B
文字コードの差分を計算するのが一番楽。Stringやらstrやらそれらのポインタやらややこしいね~~~~。
特にs.to_string().as_str()
がうまく行かないのはびっくりした。s.to_string()
が一時的な変数で、as_str()
が来ると即座にリリースされてしまうかららしい? s.to_string()を変数に束縛してやることが必要っぽい。
感想
めちゃくちゃ型安全な言語だな~~~って印象。PythonよりかはScalaやKotlin的なBetterJavaって感じの文法で、メモリについては大変気をつけなきゃいけない。
あとはオーバーフローとかを気をつけながら実装する必要があるかな。これまでのABCのAB(C)問題くらいまでRustで解き直して、良い書き方とかを見つけたい。