error[E0308]: mismatched types

期待された型と使用された型が異なっている。

パターン

パターン A

基本形

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

サンプル

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


fn main() {
    let mut _var1 = 42_i32;
    let _var2 = 42_u32;
	_var1 = _var2;
}

error[E0308]: mismatched types
 --> src\main.rs:4:13
  |
2 |     let mut _var1 = 42_i32;
  |                     ------ expected due to this value
3 |     let _var2 = 42_u32;
4 |     _var1 = _var2;
  |             ^^^^^ expected `i32`, found `u32`

解決策

可能ならキャストするとよい。


fn main() {
    let mut _var1 = 42_i32;
    let _var2 = 42_u32;
    _var1 = _var2 as i32;
}

パターン B

クロージャ型 vs クロージャ型

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

サンプル

以下では、2 行目のクロージャの型に 3 行目のクロージャを代入しようとしている。


fn main() {
    let mut _var = &(|| false);
	_var = &(|| true);
}

error[E0308]: mismatched types
 --> src\main.rs:3:9
  |
2 |     let mut _var = &(|| false);
  |                      -- the expected closure
3 |     _var = &(|| true);
  |            ^^^^^^^^^^ expected `&{closure@main.rs:2:22}`, found `&{closure@main.rs:3:11}`
  |
  = note: expected reference `&{closure@src\main.rs:2:22: 2:24}`
             found reference `&{closure@src\main.rs:3:11: 3:13}`
  = 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 _var = &(|| false) as &dyn Fn() -> _;
    _var = &(|| true);
}

パターン C

関数アイテム型 vs 関数アイテム型

関数アイテム型はたとえ引数や戻り値の型が同じでもそれぞれ異なる。
そのため、それらに互換性があると想定するとエラーになる。

サンプル

以下では、f1 型の変数に f2 型を代入しようとしている。


fn main() {
    let mut _var = f1;
    _var = f2;
}

fn f1() {}
fn f2() {}

error[E0308]: mismatched types
 --> src\main.rs:3:9
  |
2 |     let mut _var = f1;
  |                    -- expected due to this value
3 |     _var = f2;
  |            ^^ expected fn item, found a different fn item
  |
  = note: expected fn item `fn() {f1}`
             found fn item `fn() {f2}`
  = note: different fn items have unique types, even if their signatures are the same
  = help: consider casting both fn items to fn pointers using `as fn()`

解決策

関数アイテム型を関数ポインタ型にキャストするとよい。


fn main() {
    let mut _var = f1 as fn();
    _var = f2;
}

fn f1() {}
fn f2() {}

パターン D

関数アイテム型 vs 関数ポインタ型

関数アイテム型は関数ポインタ型を受け入れない (逆は可能)。
そのため、それらに互換性があると想定するとエラーになる。

サンプル

以下では、関数アイテム型の変数に関数ポインタ型を代入しようとしている。


fn main() {
    let mut _var = f1;
    _var = f2 as fn();
}

fn f1() {}
fn f2() {}

error[E0308]: mismatched types
 --> src\main.rs:3:12
  |
2 |     let mut _var = f1;
  |                    -- expected due to this value
3 |     _var = f2 as fn();
  |            ^^^^^^^^^^ expected fn item, found fn pointer
  |
  = note: expected fn item `fn() {f1}`
          found fn pointer `fn()`
  = help: consider casting the fn item to a fn pointer: `f1 as fn()`

解決策

関数アイテム型を関数ポインタ型にキャストするとよい。


fn main() {
    let mut _var = f1 as fn();
    _var = f2 as fn();
}

fn f1() {}
fn f2() {}

パターン E

HRTB ライフタイム vs 通常ライフタイム

HRTB を扱える型を期待していたが、特定のライフタイムのみ扱える型が使用された。

サンプル

以下では、任意のライフタイム引数を扱える関数ポインタに、'static のみしか扱えない関数ポインタを代入しようとしている。


fn main() {
    let mut _var = with_hrtb as fn(&_);
    _var = with_static as fn(&'static _);
}

fn with_hrtb(s: & str) {
    println!("{s}");
}

fn with_static(s: &'static str) {
    println!("{s}");
}

error[E0308]: mismatched types
 --> src\main.rs:3:11
  |
3 |     var = with_static as fn(&'static _);
  |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected fn pointer `for<'a> fn(&'a _)`
             found fn pointer `fn(&'static _)`

パターン F

HRTB を期待する型推論

HRTB - 型推論』で紹介する通り、HRTB を含んだ型は型推論できない。

そのため、関連型にそれらを含んだ型を期待していてもエラーになる。

サンプル

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


use std::fmt::Display;

fn main() {
    callback(identity, &42);
}

fn callback<F, I, O>(f: F, input: &I)
where
    F: for<'a> Fn(&'a I) -> O,
    I: Display,
    O: Display,
{
    println!("input: {}", input);
    println!("result: {}", f(input))
}

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

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

解決策 1

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


use std::fmt::Display;

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

fn callback<F, I>(f: F, input: &I)
where
    for<'a> F: FnHelper<&'a I>,
    for<'a> <F as FnHelper<&'a I>>::Output: Display,
    I: Display,
{
    println!("input: {}", input);
    println!("result: {}", f(input))
}

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

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)]

use std::fmt::Display;

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

fn callback<F, I>(f: F, input: &I)
where
    for<'a> F: Fn<(&'a I,)>,
    for<'a> <F as FnOnce<(&'a I,)>>::Output: Display,
    I: Display,
{
    println!("input: {}", input);
    println!("result: {}", f(input))
}

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