たれながし

色々雑多に書きます

Rustで競プロがしたい(その1)

前回までのあらすじ

環境構築して、Rustが着丼した。まずはHelloWorldから……ポポーイ!!!!!!!!

azulene-c10h8.hatenablog.com

今回は基本的な構文を確認して、何問か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ではなくて、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楽チンでいいね。

atcoder.jp

ABC333A

for文と出力の調整。vectorを文字列に変換する操作、もう少しスマートにできないかなぁ。

atcoder.jp

ABC333B

文字コードの差分を計算するのが一番楽。Stringやらstrやらそれらのポインタやらややこしいね~~~~。 特にs.to_string().as_str()がうまく行かないのはびっくりした。s.to_string()が一時的な変数で、as_str()が来ると即座にリリースされてしまうかららしい? s.to_string()を変数に束縛してやることが必要っぽい。

atcoder.jp

感想

めちゃくちゃ型安全な言語だな~~~って印象。PythonよりかはScalaやKotlin的なBetterJavaって感じの文法で、メモリについては大変気をつけなきゃいけない。

あとはオーバーフローとかを気をつけながら実装する必要があるかな。これまでのABCのAB(C)問題くらいまでRustで解き直して、良い書き方とかを見つけたい。