Rustでコードゴルフ

普段 [Anarchy Golf](http://golf.shinh.org/) や [Code Golf](https://code.golf/) でコードゴルフをやっている際に, 気付いたテクニックやTipsを自分なりにまとめました.
代替案やもっと良い書き方がありましたらお気軽にコメントお願いします.
※コード例に`NG`と`OK`と付けていますが, NGの例も絶対に使わないというわけではありません.

## 動作確認環境

```
$ rustc -V
rustc 1.51.0 (2fd73fabe 2021-03-23)
```

## 出力

出力は全て`print`マクロを使う.
改行する際は

```rust
print!("{}
",n)
```

とすることで, `println`マクロを使用するより1byte減らせる.

## 比較

割った余りが`0`か?

```rust
if n%3==0{}  // NG
if n%3<1{}   // OK
```

大きい数と比較

```rust
if n<832041{}  // NG
if n<1<<20{}   // OK
```

## 型注釈

```rust
let a:u8=0;  // NG
let a=0u8;   // OK
```

```rust
let s=a.iter().map(|&x|x*2).collect::<Vec<u32>>();  // NG
let s:Vec<u32>=a.iter().map(|&x|x*2).collect();     // OK
```

collectのような戻り値がジェネリックなものは, `Vec<_>`のように省略できる場合もある.

## クロージャ

同じ処理をする場合は関数にしてしまった方がbyte数は少なくなる可能性もあるだろう.
その際に再帰しないのであれば, クロージャの方が型注釈が要らないので少なくなる.

```rust
fn f(n:i32)->i32{n*2}  // NG
let f=|n|n*2;          // OK
```

## コマンドライン引数

実行時のパスを含めない場合は以下のように書く.
`std::env::args()[1..]`のようには書けない.

```rust
for a in std::env::args().skip(1){}
```

条件に一致するもののみ処理対象にするような問題では`.skip(1)`を省略できる.

```rust
for a in std::env::args(){}
```

## ループ

C言語だとfor文一択だと思いますが, Rustでは場合によりけりです.
パターン毎に使用例を提示します.

`+1`の範囲なら`=`を使う

```rust
for _ in 0..n+1{}  // NG
for _ in 0..=n{}   // OK
```

`for_each`は使わない

```rust
(0..10).for_each(|i|{});  // NG
for i in 0..10{}          // OK
```

逆順

```rust
for i in(0..10).rev(){}
//      ^ 空白を詰めれる
```

n回ループと決まっていない場合

```rust
while i<10{
    i+=if true{2}else{5}
}
```

rangeから暗黙的にイテレータにできるので以下も有効的


```rust
(0..10).fold(0,|a,x|{print!("{}",a);a+x})
```

mapはそのままでは標準出力されないことに注意.
collectすると出力される. 変数に束縛する必要はない.

```rust
(0..10).map(|n|{print!("{}",n);n}).collect()::<Vec<_>>()
```

## 変数

変数を複数使う場合はタプルを分解すると効率良い

```rust
let a=0;let b=1;let c=2;  // NG
let(a,b,c)=(0,1,2);       // OK
```

mutableな時は変数の使用回数によって使い分け

```rust
let(mut a,mut b,mut c)=(0,1,2);
let mut a=(0,1,2);
```

クロージャも使える

```rust
let(a,b)=(0,1);a+b  // NG
(|a,b|a+b)(0,1)     // OK
```

## 式

Rustはほとんどが**文**ではなく**式**で構成されている.
つまり, for式やif式から返る値を有効活用できる.

forやwhileは`()`を返す必要がある

```rust
let m=for n in 0..10{n};   // NG
let m=for n in 0..10{n;};  // OK
```

`()`を返すという特性を活かして, セミコロンを省略

```rust
for n in 0..10{print!("{}",n)}
```

## char

`'A'`はASCIIコードの10進数で`65`である.
文字列を一文字ずつ解析する場合は, `chars`より`bytes`の方が良い場合もある.

```rust
match c as _{
    65=>(),
    66=>(),
    // ...
    89=>(),
    _=>()
}
```

## 文字列

`to_string()`よりも`to_owned()`や`into()`が使えないか試す.
文字列リテラルをStringに変換する勇気も時には必要.

```rust
print!("{}",
match(i%3,i%5){
    (0,0)=>"FizzBuzz".into(),
    (0,_)=>"Fizz".into(),
    (_,0)=>"Buzz".into(),
    _=>i.to_string()
})
```

## 空白埋め

図形を描画する系の問題で使用する.

可変幅の場合

```rust
let n=42;
print!("{}"," ".repeat(n));  // NG
print!("{:<w$}","",w=n);     // NG
print!("{:<1$}","",n);       // OK
```

固定幅の場合

```rust
print!("{:^42}",n)
```

## パターンマッチ

波かっこの後ろにカンマは要らない.

```rust
match a{
    0=>{}
    1=>{}
    _=>{}
}
```

一番最後にもカンマは要らない.

```rust
match a{
    0=>"a",
    1=>"b",
    _=>"c"
}
```

rangeを使用する場合は`=`が必要.

```rust
match c{
    'a'..='z'=>(),
    '0'..='3'|'6'..='9'=>(),
    '🍣'..='🍺'=>(),
    _=>()
}
```

`if let`のような論駁可能性はenum以外でも使える.

```rust
if matches!(n,2|3|5){}  // NG
if n==2||n==3||n==5{}   // NG
if let 2|3|5=n{}        // OK
```

## キャスト

`bool`型は整数型へキャストすることで `0` `1` に変換できる

```rust
v=if i<1{0}else{n-i};  // NG
v=(i>0)as u8*n-i;      // OK
```

## ライフタイム

スコープと[ライフタイム](https://doc.rust-jp.rs/book-ja/ch10-03-lifetime-syntax.html)は別物.

```rust
// aとbのライフタイムは同じ
let a;
{
    let b=&1;
    a=b
}
print!("{}",a)  // OK
```

必要以上のライフタイムを持つ変数へ束縛することでライフタイムを伸ばすことができる.
その際, 初期化されていない変数を参照しない限り, 宣言時の初期化や`mut`は必要ない.

```rust
let n;
print!("{}",
match(i%3,i%5){
    (0,0)=>"FizzBuzz",
    (0,_)=>"Fizz",
    (_,0)=>"Buzz",
    _=>{n=i.to_string();&n}
})
```

## Never type

Rustには発散する `!` という型がある.
具体的には `break`, `return`, `panic` そして `loop`等がある.
`!` は任意の型にキャストすることができるので, こんな活用もできる.

`i`が100以上の時にループから抜けたい

```rust
if i>99{break}  // NG
i>99&&break     // OK
```

## unsafe

unsafeなコードで短縮できる場合もある.
コードゴルフで安全性は考慮する必要なし.

```rust
unsafe{
    static mut A:Vec<Vec<u8>>=vec![];
    unsafe fn f(){
        // something with using A
    }
}
```

## Webサイト

様々な問題の各種言語での解答が載っている.
Rust以外の言語で使用しているアルゴリズムも非常に参考になる.

- [codegolf.stackexchange.com/](https://codegolf.stackexchange.com/)
    ゴルファーのための質問サイト

- [TopAnswers](https://topanswers.xyz/codegolf)
    普通に問題と解答が載っている

- [Rosetta Code](http://rosettacode.org/wiki/Rosetta_Code)
    ショートコーディングではないが, コード例が載っている

## その他

- キャスト時は`as _`にできないか試す
- 実行時の警告は`RUSTFLAGS=-Awarnings`で無視できる

## 追記 - rustc 1.58.0 (02072b482 2022-01-11)

Rust 1.58からフォーマット文字列で変数を直接参照できるようになった.
1.58時点では識別子のみ有効であり、式の指定はできない。

```rust
print!("{}",i)  // NG
print!("{i}")   // OK
```