error[E0308]: mismatched types

値の型が期待されるのと異なっている。

パターン

パターン A

基本形

単純に期待されるのと異なる型を使っているパターン。

サンプル

以下では、i32 型が期待される箇所で、f32 型の値を使っている。


fn main() {
    let x = 4.2 as f32;
    let r = increment(x);
    println!("{x} + 1 = {r}");
}

fn increment(x: i32) -> i32 {
    x + 1
}

error[E0308]: mismatched types
 --> src\main.rs:3:23
  |
3 |     let r = increment(x);
  |             --------- ^ expected `i32`, found `f32`
  |             |
  |             arguments to this function are incorrect
  |
note: function defined here
 --> src\main.rs:7:4
  |
7 | fn increment(x: i32) -> i32 {
  |    ^^^^^^^^^ ------

パターン B

クロージャが関連

クロージャの型はたとえ引数や戻り値の型が同じでも一つ一つ異なる。
そのため、それらに互換性があると想定するとエラーになる。

サンプル

以下では、変数 closure の参照先を切替ようとしている。


fn main() {
    let mut closure = &(|| false);
    assert_eq!(closure(), false);

    closure = &(|| true);
    assert_eq!(closure(), true)
}

error[E0308]: mismatched types
 --> src\main.rs:5:15
  |
2 |     let mut closure = &(|| false);
  |                         -- the expected closure
...
5 |     closure = &(|| true);
  |               ^^^^^^^^^^ expected `&{closure@main.rs:2:25}`, found `&{closure@main.rs:5:17}`
  |
  = note: expected reference `&{closure@src\main.rs:2:25: 2:27}`
             found reference `&{closure@src\main.rs:5:17: 5:19}`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

解決策

型を dyn キーワードで抽象化するとよい。


fn main() {
    let mut closure = &(|| false) as &dyn Fn() -> _;
    assert_eq!(closure(), false);

    closure = &(|| true);
    assert_eq!(closure(), true)
}

パターン C

型推論が関連

型推論により型パラメタが HRTB を含む型だと期待されるとエラーになる。
(注: ライフタイム省略により for<...> 構文を使わない HRTB もありうる)。

制限の利用と回避

多くの場合、この制限は有用である。例えば、Iterator::scan のクロージャ引数では、この制限により戻り値に引数由来のライフタイムが含まれるのを禁止している。

そして、この制限が邪魔な場合、後述の解決策で解除できる。

サンプル

以下では、関数 callback の型パラメタ F の境界、そしてその実引数 identity の型から、型パラメタ OHRTB によるライフタイム 'a を含むと期待されてしまう。


fn main() {
    let input = &42;
    let result = callback(identity, input);
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I, O>(f: F, input: &I) -> O
where
    F: for<'a> Fn(&'a I) -> O
{
    f(input)
}

error[E0308]: mismatched types
  --> src\main.rs:3:18
   |
3  |     let result = callback(identity, input);
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected reference `&'a _`
              found reference `&_`
note: the lifetime requirement is introduced here
  --> src\main.rs:13:29
   |
13 |     F: for<'a> Fn(&'a I) -> O
   |                             ^

解決策 1

以下では、推論すべき箇所を型パラメタではなく関連型で表現している。なお、FnHelperFn トレイトを通常のトレイトとして扱えるようにするためのヘルパトレイトである。


fn main() {
    let input = &42;
    let result = callback(identity, input);
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I>(f: F, input: &I) -> <F as FnHelper<&I>>::Output
where
    F: for<'a> FnHelper<&'a I>
{
    f(input)
}

trait FnHelper<I>: Fn(I) -> <Self as FnHelper<I>>::Output {
    type Output;
}

impl<F, I, O> FnHelper<I> for F
where
    F: Fn(I) -> O,
{
    type Output = F::Output;
}

解決策 2

以下でも、推論すべき箇所を型パラメタではなく関連型で表現している。ただし、前の解決策とは異なり、FnHelper の代わりに まだ不安定な機能 unboxed_closures を利用している。


#![feature(unboxed_closures)]

fn main() {
    let input = &42;
    let result = callback(identity, input);
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I>(f: F, input: &I) -> <F as FnOnce<(&I,)>>::Output
where
    F: for<'a> Fn<(&'a I,)>
{
    f(input)
}