2
1

[Rust] Result<T, E> 型から Result<U, F> 型への変換

Last updated at Posted at 2023-11-09

0. まとめ

用途別:

  • Ok から Ok へおよび Err から Err への変換
    • map
    • map_err
    • map_or_else
  • Ok から Err へおよび Err から Ok への変換
    • and_then
    • or_else
    • map_or_else
  • 値同士を結合
    • and_then
    • or_else
  • 参照
    • as_ref, as_deref, as_mut, as_deref_mut
  • 複製
    • clone, clone_from
    • copied, cloned

map_or メソッドも map_or_else メソッドと同じことができますが、値を遅延評価するために本記事では map_or_else メソッドを使用します。
and メソッドも and_then メソッドと同じことができますが、値を遅延評価するために本記事では map_or_else メソッドを使用します。
or メソッドも or_else メソッドと同じことができますが、値を遅延評価するために本記事では map_or_else メソッドを使用します。

// 
pub fn map<U>(self: Result<T, E>, op: impl FnOnce(T) -> U) -> Result<U, E>
pub fn map_err<F>(self: Result<T, E>, op: impl FnOnce(E) -> F) -> Result<T, F>

// 
pub fn map_or_else<U>(self: Result<T, E>, default: impl FnOnce(E) -> U, f: impl FnOnce(T) -> U) -> U

// 
pub fn and_then<U>(self: Result<T, E>, op: impl FnOnce(T) -> Result<U, E>) -> Result<U, E>
pub fn or_else<F>(self: Result<T, E>, op: impl FnOnce(E) -> Result<T, F>) -> Result<T, F>

// 
pub fn as_ref(self: &Result<T, E>) -> Result<&T, &E>
pub fn as_deref(self: &Result<T, E>) -> Result<&T::Target, &E>
where
    T: Deref,

pub fn as_mut(self: &mut Result<T, E>) -> Result<&mut T, &mut E>
pub fn as_deref_mut(self: &mut Result<T, E>) -> Result<&mut T::Target, &mut E>
where
    T: DerefMut,

// 
pub fn clone(self: &Result<T, E>) -> Result<T, E>
pub fn clone_from(self: &mut Result<T, E>, source: &Result<T, E>)

// 
pub fn copied(self: Result<&T, E>) -> Result<T, E>
where
    T: Copy,
pub fn cloned(self: Result<&T, E>) -> Result<T, E>
where
    T: Clone,
pub fn copied(self: Result<&mut T, E>) -> Result<T, E>
where
    T: Copy,
pub fn cloned(self: Result<&mut T, E>) -> Result<T, E>
where
    T: Clone,

参考「map - Result in std::result - Rust
参考「map_err - Result in std::result - Rust

参考「map_or_else - Result in std::result - Rust

参考「and_then - Result in std::result - Rust
参考「or_else - Result in std::result - Rust

参考「as_ref - Result in std::result - Rust
参考「as_deref - Result in std::result - Rust
参考「as_mut - Result in std::result - Rust
参考「as_deref_mut - Result in std::result - Rust

参考「clone - Result in std::result - Rust
参考「clone_from - Result in std::result - Rust

参考「copied - Result in std::result - Rust
参考「cloned - Result in std::result - Rust
参考「copied - Result in std::result - Rust
参考「cloned - Result in std::result - Rust

1. Ok から Ok へおよび Err から Err への変換

1.1. Result<T, E> 型から Result<U, E> 型への変換

Ok の値のみ変換する場合は map メソッドを用います。

let f = |t: i64| t.to_string();

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Err(42);

let y1: Result<String, i64> = x1.map(f);
let y2: Result<String, i64> = x2.map(f);

println!("{:?}", y1);
println!("{:?}", y2);
実行結果
Ok("23")
Err(42)

1.2. Result<T, E> 型から Result<T, F> 型への変換

Err の値のみ変換する場合は map_err メソッドを用います。

let f = |e: i64| e.to_string();

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Err(42);

let y1: Result<i64, String> = x1.map_err(f);
let y2: Result<i64, String> = x2.map_err(f);

println!("{:?}", y1);
println!("{:?}", y2);
実行結果
Ok(23)
Err("42")

1.3. Result<T, E> 型から Result<U, F> 型への変換

OkErr の両方の値を変換するメソッドは (少なくともバージョン 1.73.0 現在は) 標準では提供されないため、map_or_else メソッドを用いて変換します。

(※ map_or メソッドでも同様のことができますが、map_or メソッドを用いると selfOk の場合でも Err 用の引数の計算を正格評価で行ってしまうため、map_or_else メソッドを用いて引数を遅延評価します。)
(※ map メソッドと map_err メソッドを組み合わせることでも同様のことができますが、最適化を考慮しない場合は計算コストが増加します。)

let f = |t: i64| t.to_string();
let g = |e: i64| e.to_string();

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Err(42);

let y1: Result<String, String> = x1.map_or_else(|e| Err(g(e)), |t| Ok(f(t)));
let y2: Result<String, String> = x2.map_or_else(|e| Err(g(e)), |t| Ok(f(t)));

println!("{:?}", y1);
println!("{:?}", y2);
実行結果
Ok("23")
Err("42")

2. Ok から Err へおよび Err から Ok への変換

2.1. Result<T, E> 型から Result<U, E> 型への変換

Ok の値を Ok または Err の値に変換する場合は and_then メソッドを用います。

let f = |t: i64| if t >= 0 { Ok(t.to_string()) } else { Err(t) };

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Ok(-23);
let x3: Result<i64, i64> = Err(42);
let x4: Result<i64, i64> = Err(-42);

let y1: Result<String, i64> = x1.and_then(f);
let y2: Result<String, i64> = x2.and_then(f);
let y3: Result<String, i64> = x3.and_then(f);
let y4: Result<String, i64> = x4.and_then(f);

println!("{:?}", y1);
println!("{:?}", y2);
println!("{:?}", y3);
println!("{:?}", y4);
実行結果
Ok("23")
Err(-23)
Err(42)
Err(-42)

2.2. Result<T, E> 型から Result<T, F> 型への変換

Err の値を Ok または Err の値に変換する場合は or_else メソッドを用います。

let f = |e: i64| if e >= 0 { Ok(e) } else { Err(e.to_string()) };

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Ok(-23);
let x3: Result<i64, i64> = Err(42);
let x4: Result<i64, i64> = Err(-42);

let y1: Result<i64, String> = x1.or_else(f);
let y2: Result<i64, String> = x2.or_else(f);
let y3: Result<i64, String> = x3.or_else(f);
let y4: Result<i64, String> = x4.or_else(f);

println!("{:?}", y1);
println!("{:?}", y2);
println!("{:?}", y3);
println!("{:?}", y4);
実行結果
Ok(23)
Ok(-23)
Ok(42)
Err("-42")

2.3. Result<T, E> 型から Result<U, F> 型への変換

OkErr の相互変換をする場合は map_or_else メソッドを用います。

let f = |t: i64| {
    if t >= 0 {
        Ok(t.to_string())
    } else {
        Err(t.to_string())
    }
};
let g = |e: i64| {
    if e >= 0 {
        Ok(e.to_string())
    } else {
        Err(e.to_string())
    }
};

let x1: Result<i64, i64> = Ok(23);
let x2: Result<i64, i64> = Ok(-23);
let x3: Result<i64, i64> = Err(42);
let x4: Result<i64, i64> = Err(-42);

let y1: Result<String, String> = x1.map_or_else(g, f);
let y2: Result<String, String> = x2.map_or_else(g, f);
let y3: Result<String, String> = x3.map_or_else(g, f);
let y4: Result<String, String> = x4.map_or_else(g, f);

println!("{:?}", y1);
println!("{:?}", y2);
println!("{:?}", y3);
println!("{:?}", y4);
実行結果
Ok("23")
Err("-23")
Ok("42")
Err("-42")

3. 値同士を結合する

3.1. Result<T, E> 型から Result<U, E> 型への変換

and_then メソッドは、2 値が両方とも Ok なら Ok を返し、それ以外は Err を返す目的でも使用できます。

(※ and メソッドでも同様のことができますが、and メソッドを用いると selfErr の場合でも引数の計算を正格評価で行ってしまうため、and_then メソッドを用いて引数を遅延評価します。)

let x1: Result<i64, &str> = Ok(23);
let x2: Result<i64, &str> = Err("Error: x");

let y1: Result<&str, &str> = x1.and_then(|_| Ok("Foo"));
let y2: Result<&str, &str> = x1.and_then(|_| Err("Error: y"));
let y3: Result<&str, &str> = x2.and_then(|_| Ok("Foo"));
let y4: Result<&str, &str> = x2.and_then(|_| Err("Error: y"));

println!("{:?}", y1);
println!("{:?}", y2);
println!("{:?}", y3);
println!("{:?}", y4);
実行結果
Ok("Foo")
Err("Error: y")
Err("Error: x")
Err("Error: x")

3.2. Result<T, E> 型から Result<T, F> 型への変換

or_else メソッドは、2 値のどちらか一方が Ok なら Ok を返し、それ以外は Err を返す目的でも使用できます。

(※ or メソッドでも同様のことができますが、or メソッドを用いると selfOk の場合でも引数の計算を正格評価で行ってしまうため、or_else メソッドを用いて引数を遅延評価します。)

let x1: Result<&str, i64> = Ok("Foo");
let x2: Result<&str, i64> = Err(23);

let y1: Result<&str, &str> = x1.or_else(|_| Ok("Bar"));
let y2: Result<&str, &str> = x1.or_else(|_| Err("Error: y"));
let y3: Result<&str, &str> = x2.or_else(|_| Ok("Bar"));
let y4: Result<&str, &str> = x2.or_else(|_| Err("Error: y"));

println!("{:?}", y1);
println!("{:?}", y2);
println!("{:?}", y3);
println!("{:?}", y4);
実行結果
Ok("Foo")
Ok("Foo")
Ok("Bar")
Err("Error: y")

4. 参照

Ok および Err の中身の値を借用します。

Ok に関しては中身の値を借用かつ deref() することもできます。

let x1: Result<String, i64> = Ok("Foo".to_string());
let x2: Result<String, i64> = Err(23);

// 
let y1: Result<&String, &i64> = x1.as_ref();
let y2: Result<&String, &i64> = x2.as_ref();

let y1: Result<&str, &i64> = x1.as_deref();
let y2: Result<&str, &i64> = x2.as_deref();
let mut x1: Result<String, i64> = Ok("Foo".to_string());
let mut x2: Result<String, i64> = Err(23);

//
let y1: Result<&mut String, &mut i64> = x1.as_mut();
let y2: Result<&mut String, &mut i64> = x2.as_mut();

let y1: Result<&mut str, &mut i64> = x1.as_deref_mut();
let y2: Result<&mut str, &mut i64> = x2.as_deref_mut();

5. 複製

Ok および Err の外身の値を複製する場合は clone メソッドまたは clone_from メソッドを用います。

let x: Result<i64, i64> = Ok(23);

// 
let y: Result<i64, i64> = x.clone();

let mut y: Result<i64, i64> = x.clone();
y.clone_from(&x);

Ok の中身の値を複製する場合は copied メソッドまたは cloned メソッドを用います。

//
let value = 23;
let x: Result<&i64, i64> = Ok(&value);
let y: Result<i64, i64> = x.copied();

let value = 23;
let x: Result<&i64, i64> = Ok(&value);
let y: Result<i64, i64> = x.cloned();

//
let value = "Foo".to_string();
let x: Result<&String, i64> = Ok(&value);
let y: Result<String, i64> = x.cloned();

//
let mut value = 23;
let x: Result<&mut i64, i64> = Ok(&mut value);
let y: Result<i64, i64> = x.copied();

let mut value = 23;
let x: Result<&mut i64, i64> = Ok(&mut value);
let y: Result<i64, i64> = x.cloned();

//
let mut value = "Foo".to_string();
let x: Result<&mut String, i64> = Ok(&mut value);
let y: Result<String, i64> = x.cloned();
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1