Отказ от ответственности: этот ответ предполагает, что читатель понимает, что -> impl Trait
требует возврата одного типа;см. этот вопрос о возврате различных типов .
Непрозрачность
Один из основных принципов Rust заключается в том, что проверка типов полностью определяется интерфейс функций, типов и т. Д ... и реализация игнорируется.
Что касается функциональности -> impl Trait
, это проявляется в том, что язык обрабатывает каждый -> impl Trait
как непрозрачный тип, определяется только той функцией, из которой она взята.
В результате вы можете вызывать одну и ту же функцию дважды:
use std::fmt::Debug;
fn cat(name: &str) -> impl Debug { format!("Meow {}", name) }
fn meow(g: bool) -> impl Debug {
if g {
cat("Mario")
} else {
cat("Luigi")
}
}
fn main() {
println!("{:?}", meow(true));
}
Но вы не можете вызывать разные функции, даже если они возвращают одну и ту же функцию.тип, если хотя бы один спрятан за -> impl Trait
:
use std::fmt::Debug;
fn mario() -> impl Debug { "Meow Mario" }
fn luigi() -> &'static str { "Meow Luigi" }
fn meow(g: bool) -> impl Debug {
if g {
mario()
} else {
luigi()
}
}
fn main() {
println!("{:?}", meow(true));
}
Выход:
error[E0308]: if and else have incompatible types
--> src/main.rs:8:9
|
8 | / if g {
9 | | mario()
10 | | } else {
11 | | luigi()
12 | | }
| |_________^ expected opaque type, found &str
|
= note: expected type `impl std::fmt::Debug`
found type `&str`
И с двумя спрятанными за -> impl Trait
:
use std::fmt::Debug;
fn mario() -> impl Debug { "Meow Mario" }
fn luigi() -> impl Debug { "Meow Luigi" }
fn meow(g: bool) -> impl Debug {
if g {
mario()
} else {
luigi()
}
}
fn main() {
println!("{:?}", meow(true));
}
Возвращает то же сообщение об ошибке, что и вы:
error[E0308]: if and else have incompatible types
--> src/main.rs:8:5
|
8 | / if g {
9 | | mario()
10 | | } else {
11 | | luigi()
12 | | }
| |_____^ expected opaque type, found a different opaque type
|
= note: expected type `impl std::fmt::Debug` (opaque type)
found type `impl std::fmt::Debug` (opaque type)
Взаимодействие с рекурсией
Нет.
Язык здесь не имеет особой рекурсии и поэтому не понимает, что в случае pОбиженный в вопросе, есть только один вовлеченный тип.Вместо этого он замечает fn one(...) -> impl Meow
и fn two(...) -> impl Meow
и приходит к выводу, что это разные непрозрачные типы, и поэтому объединение во время компиляции невозможно.
Может быть разумным представить RFC для настройки этого аспекта,либо аргументируя точку зрения рекурсии, либо аргументируя видимость видимости на уровне модуля;это выходит за рамки этого ответа.
Обход
Единственная возможность состоит в том, чтобы гарантировать, что тип является уникальным , и это требует имя это.После того, как вы запечатлели тип в имени, вы можете последовательно применять его везде, где оно должно соответствовать.
Я отошлю вас к @ Anders's answer за его умный обходной путь.