Rustの文字列を数値にキャストする時にプリミティブではないと言われた場合

asによる型変換はプリミティブでしか行えません

fn main() {
    let string_number = "3600".to_string();
    assert_eq!(string_number as u64, 3600 as u64);
}

この結果はこうなります

error[E0605]: non-primitive cast: `std::string::String` as `u64`
 --> src/main.rs:3:16
  |
3 |     assert_eq!(string_number as u64, 3600 as u64);
  |                ^^^^^^^^^^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

上記エラーを解決するにはparseを使えば良いです。

fn main() {
    let string_number = "3600".to_string();
    assert_eq!(string_number.parse::<u64>().unwrap(), 3600 as u64);
}

参考

https://qiita.com/smicle/items/29a4d5d1d14ad7f77f60

Rustの疑問符演算子の使い方

try!マクロとほぼ同等の機能を持っている。そこから察して下記の機能がある。

  • Result型を返すスコープ内で使える
    • Errではなければunwrap()と同等の結果を返す
    • Errであるとreturn Err()の挙動をする
  • Fromを実装することでオリジナルエラーから独自エラーへの変換が可能

?を使わない場合

欲するのはErrorだが、処理の中でreturnされるErr()になっているので、map_errを返して手動でErrorに変換している。

#[derive(Debug, PartialEq, Clone)]
enum Error {
    Example
}

fn main() {
    let test = (|| -> Result<(), Error> {
        Err(()).map_err(|_| Error::Example)
    })();

    assert_eq!(Err(Error::Example), test);
}

?を使う場合

Fromを実装することで?を書くだけで、上記と同じ結果を返している。コード量が増えているように見えるが、同等の記述が必要なところが複数現れたときに、すぐに上記の方がコード量が多くなることが想像できる。

#[derive(Debug, PartialEq, Clone)]
enum Error {
    Example
}

impl From<()> for Error {
    fn from(_: ()) -> Self {
        Error::Example
    }
}

fn main() {
    let test = (|| -> Result<(), Error> {
        Err(())?
    })();

    assert_eq!(Err(Error::Example), test);
}

参考

RustのOption型をmapとand_thenで上手に取り出す

以前matchについて書きました。今回はmapand_thenというコンビネータを利用した値の取り出しについて書いてみます。

map

mapは値を加工できるが、型自体を変更できない。SomeはSome、NoneはNoneになる。

fn main() {

    let case1: Option<i8> = Some(1);
    let case2: Option<i8> = None;

    assert_eq!(case1.map(|n| n * 2 ), Some(2));
    assert_eq!(case2.map(|n| n * 2 ), None);
}

and_then

and_then は返す型を変更できる。

fn main() {

    let case1: Option<i8> = Some(1);
    let case2: Option<i8> = Some(2);

    assert_eq!(case1.and_then(|n| if n == 2 { Some(n) } else { None }), None);
    assert_eq!(case2.and_then(|n| if n == 2 { Some(n) } else { None }), Some(2));
}

Vimでリモートホストのファイルを編集する

Vimでファイルを編集して保存するとリモートにファイルが作成されました。直接リモートに入ってviで開くとその環境のvimrcなどが使われますが、この方式を使えば手元のvimの設定でファイルを編集することができます。

vim scp://user@remote//path/to/hoge.text

https://orebibou.com/2015/02/vim%E3%81%A7%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E5%85%88%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92ssh%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB%E7%B5%8C%E7%94%B1%E3%81%A7%E7%B7%A8/

RustのVec<Result<_>>をResult<Vec<_>>に変換する

Resultを持つ配列で、Okなものを取り出すのにfilterしていて面倒だなと思ったら、どうやらVec<Result<_>>Result<Vec<_>>に変換することができるんですって。これをするとOkだけが含まれている場合はOkだけを返し、Errが一つでも含まれているとErrを返してくれるので、より実用に沿ったコードが書ける。

fn main() {
    assert_eq!([Ok(1), Ok(2), Ok(3)].iter().cloned().collect::<Result<Vec<i8>, u8>>(), Ok(vec![1, 2, 3]));
    assert_eq!([Err(1), Err(2), Ok(3)].iter().cloned().collect::<Result<Vec<i8>, u8>>(), Err(1));
}

なぜこれができるのか。細かな応用の説明は下記が参考になりました。

https://qnighy.hatenablog.com/entry/2017/06/14/220000