Есть ли какой-нибудь способ намекнуть компилятору, что меня не волнует None
или использовать какое-то значение по умолчанию?
Вы можете реализовать свое собственное неуниверсальное значениеслужить по умолчанию. Для начала давайте предположим, что print_iter
не принял Option<T>
, но сам по себе перечисление:
enum PrintArg<T> {
Ignore,
Use(T),
}
fn print_iter<T: IntoIterator<Item = i32>>(v: PrintArg<T>) {
if let PrintArg::Use(v) = v {
for e in v {
println!("{}", e);
}
}
}
Это еще не решает проблему, потому что если вы передадите PrintArg::Ignore
в print_iter()
, вы вернулись на круги своя - компилятор не может вывести T
. Но с вашим собственным типом вы можете легко изменить print_iter
, чтобы принимать все, что может быть преобразовано в PrintArg
:
fn print_iter<T, V>(v: T)
where
T: Into<PrintArg<V>>,
V: IntoIterator<Item = i32>,
{
if let PrintArg::Use(v) = v.into() {
for e in v {
println!("{}", e);
}
}
}
С помощью этой модификации,вы можете создать фиктивное неуниверсальное значение Ignore
и использовать черту From
, чтобы определить ее преобразование в PrintArg::Ignore<T>
с T
по вашему выбору - например:
struct Ignore;
impl From<Ignore> for PrintArg<Vec<i32>> {
fn from(_v: Ignore) -> Self {
PrintArg::Ignore
}
}
Поскольку Ignore
не является универсальным, его использование не требует (или не принимает) <T>
. Хотя нам и пришлось изобрести тип для PrintArg<T>
в реализации черты From
, мы никогда не конструируем его, поэтому не имеет значения, какой из них мы выберем, пока он удовлетворяет границе IntoIterator
.
Конечно, вы все равно захотите вызывать print_iter()
с Some(...)
, поэтому вы также определите преобразование Option<T>
в PrintArg<T>
:
impl<T> From<Option<T>> for PrintArg<T> {
fn from(v: Option<T>) -> Self {
match v {
Some(v) => PrintArg::Use(v),
None => PrintArg::Ignore,
}
}
}
. место, ваш API чист, что позволяет main()
выглядеть так ( детская площадка ):
fn main() {
let v = vec![1i32, 2, 3];
print_iter(Some(v));
print_iter(Ignore);
}