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();
- https://docs.rs/chrono/0.4.19/chrono/offset/trait.TimeZone.html?search=#method.timestamp_millis_opt
- https://qiita.com/fujitayy/items/ae6175118cbed7134594#unix-time%E3%81%8B%E3%82%89%E3%81%AE%E5%A4%89%E6%8F%9B
DateTime<UTC>
-> unixtimestamp(millis)
let timestamp: i64= Utc::now().timestamp_millis();
- https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html#method.timestamp_millis
- https://qiita.com/fujitayy/items/ae6175118cbed7134594#unix-time%E3%81%B8%E3%81%AE%E5%A4%89%E6%8F%9B
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());
Comments