error[E0308]: mismatched types
値の型が期待されるのと異なっている。
単純に期待されるのと異なる型を使っているパターン。
以下では、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 { | ^^^^^^^^^ ------
クロージャの型はたとえ引数や戻り値の型が同じでも一つ一つ異なる。
そのため、それらに互換性があると想定するとエラーになる。
以下では、変数 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)
}
型推論により型パラメタが HRTB を含む型だと期待されるとエラーになる。
(注: ライフタイム省略により for<...>
構文を使わない HRTB もありうる)。
多くの場合、この制限は有用である。例えば、Iterator::scan
のクロージャ引数では、この制限により戻り値に引数由来のライフタイムが含まれるのを禁止している。
そして、この制限が邪魔な場合、後述の解決策で解除できる。
以下では、関数 callback
の型パラメタ F
の境界、そしてその実引数 identity
の型から、型パラメタ O
が HRTB
によるライフタイム '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 | ^
以下では、推論すべき箇所を型パラメタではなく関連型で表現している。なお、FnHelper
は Fn
トレイトを通常のトレイトとして扱えるようにするためのヘルパトレイトである。
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;
}
以下でも、推論すべき箇所を型パラメタではなく関連型で表現している。ただし、前の解決策とは異なり、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)
}