Это кажется проблемой только из-за нескольких исключительных особенностей, связанных с типом модуля. ()
:
()
используется по умолчанию, когда тип возвращаемого значения опущен в сигнатуре функции ( поэтому fn main()
эквивалентно fn main() -> ()
); - И даже если вы не предоставили какое-либо выражение для возврата, пустые блоки или операторы в код также оценивается как
()
.
Пример ниже работает, потому что точка с запятой превращает выражение 5
в оператор, значение которого, следовательно, отбрасывается.
fn foo() {
5;
}
Рекурсивно для всех спичечных рук легко вычислить ()
, когда ни одно из них не дает результат другого типа. Это имеет место при использовании return
, потому что оператор return создает истинное расхождение с потоком выполнения: он оценивает тип never !
, который приводит к любому другому типу .
fn foo(bar: i32) {
match bar {
1 => {
return do_good_things(); // coerces to () because of the default match arm
}
0 => {
return do_other_things(); // coerces to () because of the default match arm
}
_ => {
// arm evaluates to (), oops
}
}
}
Повсеместное распространение этого типа модулей обычно способствует элегантному коду. Однако в этом случае он может вызвать ложное срабатывание, если предполагается более строгий поток управления. У компилятора нет способа разрешить это , если мы не введем другой тип для противодействия ему .
Следовательно, возможны следующие решения:
- Используйте другое тип возвращаемого значения для функции. Если нет ничего подходящего для возврата (например, только побочные эффекты), вы можете использовать почти любой тип, но другой тип единицы дает лучшую уверенность в том, что он станет абстракцией с нулевой стоимостью.
Детская площадка
struct Check;
fn foo(bar: i32) -> Check {
match bar {
1 => {
do_good_things();
Check
}
0 => {
do_other_things();
return Check; // can use return
}
_ => {
// error[E0308]: expected struct Check, found ()
}
}
}
Не используйте операторы
return
или
break
и устанавливайте sh, что все ваши спички должны оцениваться не как
()
.
Игровая площадка
struct Check;
fn foo(bar: i32) {
let _: Check = match bar {
1 => {
do_good_things();
Check
}
0 => {
do_other_things();
Check
}
_ => {
// error[E0308]: expected struct Check, found ()
}
};
}
Обратное: устанавливает sh, что выражение сопоставления оценивается как нулевой тип (такой как тип never
!
), так что никакая рука сопоставления не может вернуться из него, за исключением использования операторов потока управления, таких как
break
или
return
.
Детская площадка
enum Nope {}
fn foo(bar: i32) {
let _: Nope = match bar {
1 => {
return do_good_things();
}
0 => {
return do_other_things();
}
_ => {
// error[E0308]: expected enum `Nope`, found ()
}
};
}
См. Также: