Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
76
Help us understand the problem. What is going on with this article?
@legokichi

Rust の型変換イディオム

Rust の型変換イディオム

この記事は Rustその2 Advent Calendar 2018 の 12 日目の記事です。

Option<String> to Option<&str>

let a: Option<String> = Some("0".to_string());
let b: Option<&str> = a.as_deref();
// または let b: Option<&str> = a.as_ref().map(AsRef::as_ref);

Option<Vec<T>> -> Option<&[T]>

let a: Option<Vec<u8>> = Some(vec![0]);
let b: Option<&[u8]> = a.as_deref();

Option<Rc<T>> -> Option<&T>, Option<Arc<T>> -> Option<&T>

Option::as_deref は Option の中の型が Deref トレイトを実装しているときに Deref::Target の参照へ変換できる

use std::rc::Rc;
let a: Option<Rc<u8>> = Some(Rc::new(0));
let b: Option<&u8> = a.as_deref();

Option<String> to &Option<&str>

let a: Option<String> = Some("0".to_string());
let b: Option<&str> = a.as_ref().map(AsRef::as_ref);
let c: &Option<&str> = &b;

Vec<String> to &[&str]

let a: Vec<String> = vec!["0".to_string()];
let b: Vec<&str> = a.iter().map(AsRef::as_ref).collect();
let c: &[&str] = b.as_ref();

Option<Vec<String>> -> &Option<&[&str]>

let a: Option<Vec<String>> = Some(vec!["0".to_string()]);
let b: Option<&[String]> = a.as_ref().map(AsRef::as_ref);
let c: Option<Vec<&str>> = b.map(|lst| lst.iter().map(|s| s.as_ref()).collect::<Vec<_>>());
let d: Option<&[&str]> = c.as_ref().map(|lst| lst.as_ref());
let a: Option<String> = Some("0".to_owned());
let b: Option<&String> = a.as_ref();
let c: Option<&str> = b.map(|x| &**x);
let d: &Option<&str> = &c; //   ||||
                                |||+ x: &String
                                ||+ *x: String
                                |+ **x: str:  (*<String as Deref<Target = str>>::deref(*x))
                                + &**x: &str 

Option<T> to Option<&T>

let a: Option<i32> = Some(0);
let b: Option<&i32> = a.as_ref();

Result<T, E> to Result<&T, &E>

let a: Result<i32, ()> = Ok(0);
let b: Result<&i32, &()> = a.as_ref();

String -> &str

let a: String = "0".to_string();
let b: &str = &a.to_string()[..];
let a: String = "0".to_string();
let b: &str = &*a;

Result<T, E> -> Option<T>

let a: Result<i32, ()> = Ok(0);
let b: Option<i32> = a.ok();

Result<T, E> -> Option<E>

let a: Result<i32, ()> = Ok(0);
let b: Option<()> = a.err();

Option<T> -> Result<T, E>

let a: Option<i32> = Some(0);
let b: Result<i32, ()> = a.ok_or(());
let a: Option<i32> = Some(0);
let b: Result<i32, ()> = a.ok_or_else(|| ());

Option<T> -> Vec<T>

let a: Option<i32> = Some(0);
let b: Vec<i32> = a.into_iter().collect::<Vec<_>>();

Option<T> -> Vec<&T>

let a: Option<i32> = Some(0);
let b: Vec<&i32> = a.iter().collect::<Vec<_>>();

Vec<T> -> Option<T>

let a: Vec<i32> = vec![0];
let b: Option<i32> = a.into_iter().next();

Vec<T> -> Option<&T>

let a: Vec<i32> = vec![0];
let b: Option<i32> = a.first();

Option<Option<T>> -> Option<T>

let a: Option<Option<i32>> = Some(Some(0));
let b: Option<i32> = a.and_then(|opt| opt);

Result<Option<T>, E> -> Option<Result<T, E>>

let a: Result<Option<i32>, ()> = Ok(Some(0));
let b: Option<Result<i32, ()>> = match a {
    Ok(Some(x)) => Some(Ok(x)),
    Ok(None) => None,
    Err(e) => Some(Err(e)),
};

Option<Result<T, E>> -> Result<Option<T>, E>

let a: Option<Result<i32, ()>> = Some(Ok(0));
let b: Result<Option<i32>, ()> = match self {
    Some(Ok(x)) => Ok(Some(x)),
    Some(Err(e)) => Err(e),
    None => Ok(None),
};

Vec<Result<T, E>> -> Result<Vec<T>, E>

let a: Vec<Result<i32, ()>> = vec![Ok(0), Err(())];
let b: Result<Vec<i32>, ()> = a.into_iter().collect();
assert_eq!(b, Err(()));

Vec<Option<T>> -> Option<Vec<T>>

let a: Vec<Option<i32>> = vec![Some(0), None];
let b: Option<Vec<i32>> = a.into_iter().collect();
assert_eq!(b, None);

&T -> &[T] (Tの参照から要素1のTのスライスの参照への変換)

let a: u32 = 0;
let a_slice: &[u32] = std::slice::from_ref(&a);

&str -> &[u8]

let a: &str = "0";
let b: &[u8] = a.as_bytes();

String -> Vec<u8>

let a: String = "0".to_string();
let b: Vec<u8> = a.into_bytes();

&[u8] -> &str

let a: &[u8] = &[48];
let b: &str = std::str::from_utf8(a).unwrap();
assert_eq!("0", b);

Vec<u8> -> String

let a: Vec<u8> = vec![48];
let b: String = String::from_utf8(a).unwrap();
assert_eq!("0".to_string(), b);

String, &str -> u8, u16, u32 u64, usize, i8, i16, i32, i64, isize, f32, f64 (文字列から数値への変換)

let a: &str = "0";
let b: u8 = a.parse::<u8>().unwrap();

let a: String = "48".to_string();
let b: f64 = a.parse::<f64>().unwrap();

u8 -> u16 -> u32 -> u64 (安全なアップキャスト)

安全なアップキャスト

let a: u8 = 0;
let b: u16 = From::from(a);
let c: u32 = From::from(b);
let d: u64 = From::from(c);

u64 -> u32 -> u16 -> u8 (安全なダウンキャスト)

use std::convert::TryFrom;

let a: u64 = 255;
let b: u32 = TryFrom::try_from(a).unwrap();
let c: u16 = TryFrom::try_from(b).unwrap();
let d: u8 = TryFrom::try_from(c).unwrap();

as でパニックさせずにキャストするには境界チェックが必要

fn i64_to_i8(u: i64) -> Option<i8> {
    let min = u8::min_value() as i64;
    let max = u8::max_value() as i64;
    if u < min || u > max {
        None
    } else {
        Some(u as i8)
    }
}

let a: i64 = 255;
let b: i8 = i64_to_i8(a).unwrap();

任意の struct を Vec<u8> に変換

対象の struct がすべて自分のクレートのとき => bincode + serde を使う

#[derive(Serialize, Default)]
struct MyStruct {
    id: u8,
    data: [u8; 1024],
}

fn main() {
    let my_struct = MyStruct::default();
    let bytes: Vec<u8> = bincode::serialize(&my_struct).unwrap();
}

対象の struct が別クレート or bindgen などで自動生成されていて、Sized(コンパイル時に大きさが決まっている) のとき => std::slice::from_raw_parts を使う

unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
    std::slice::from_raw_parts(
        (p as *const T) as *const u8,
        std::mem::size_of::<T>(),
    )
}

#[derive(Default)]
struct MyStruct {
    id: u8,
    data: [u8; 1024],
}

fn main() {
    let my_struct = MyStruct::default();
    let bytes: &[u8] = unsafe { any_as_u8_slice(&my_struct) };
    println!("{:?}", bytes);
}

unixtimestamp(millis) -> DateTime<UTC>

use chrono::offset::TimeZone;
let dt: DateTime<Utc> = Utc.timestamp_millis_opt(0).unwrap();

DateTime<UTC> -> unixtimestamp(millis)

let timestamp: i64= Utc::now().timestamp_millis();

ISO8601(RFC3339) -> DateTime<Utc>

let date = DateTime::parse_from_rfc3339("0000-01-01T00:00:00.000000000Z").unwrap().with_timezone(&Utc),

DateTime<Utc> -> ISO8601(RFC3339) (millis)

let date_str = Utx::now().to_rfc3339_opts(SecondsFormat::Millis, true); // 2018-01-26T18:30:09.453Z"

&'a str -> Box<dyn std::error::Error + Send + Sync + 'a>

驚くべきことに std::boxed::Box

impl<'a, '_> From<&'_ str> for Box<dyn Error + Send + Sync + 'a>

実装しているので

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    let a_boxed_error: Box<dyn std::error::Error + Send + Sync + '_> = "error!".into();
    Err(a_boxed_error)?;
    Ok(())
}

と書くことができる

String -> Box<dyn Error + Send + Sync + 'static>

同上

let a_boxed_error: Box<dyn std::error::Error + Send + Sync + 'static> = Box::from("a".to_string());
76
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
76
Help us understand the problem. What is going on with this article?