Для каналов в стандартной библиотеке самый полезный ответ - "нет ни одного".
Технически правильный ответ - макрос select!
:
select! {
r = result.recv() => {
// do something
}
_ = something_that_waits_a_second.recv() => {
// timeout
}
}
(Обратите внимание, что это эквивалент оригинального примера OP до того, как он был радикально изменен).
Это нестабильно, поэтому я классифицирую его как бесполезное.
Помимо стабильности select!
есть и другие проблемы. Например, в вашем примере Go вы создаете что-то, что волшебным образом отправляется в канал через некоторое время (time.After(time.Second)
). У Rust нет постоянно работающей среды для управления этими вещами. Это означает, что вам нужно будет создать поток уровня ОС, чтобы подождать некоторое время, и вставить значение в канал, чтобы выполнить этот тайм-аут! Это довольно неэффективно.
Если вы действительно ищете что-то ближе к зеленым нитям Go, я бы посоветовал вместо этого заглянуть в будущее:
extern crate futures; // 0.1.23
extern crate tokio; // 0.1.8
use futures::{future::Either, prelude::*, stream};
use std::time::{Duration, Instant};
use tokio::timer::{Delay, Interval, Timeout};
fn example() -> impl Stream<Item = String, Error = &'static str> {
let goog = google_search();
let bing = bing_search();
let combined = goog.select(bing);
let deadline = Delay::new(Instant::now() + Duration::from_secs(1))
.map_err(drop)
.into_stream();
let combined = combined.map(Either::A);
let deadline = deadline.map(Either::B);
combined.select(deadline).then(|r| match r {
Ok(Either::A(r)) => Ok(r),
Ok(Either::B(_)) => Err("timeout"),
Err(_) => Err("unexpected error"),
})
}
fn main() {
tokio::run({
example()
.map_err(|e| println!("Got an error: {}", e))
.for_each(|r| {
println!("Search result: {}", r);
Ok(())
})
});
}
fn google_search() -> impl Stream<Item = String, Error = ()> {
let results = (0..10).map(|x| format!("goog{}", x));
let results = stream::iter_ok(results);
// Fake some delay between results
let delay = Interval::new_interval(Duration::from_millis(75));
results.zip(delay).map(|(r, _)| r).map_err(drop)
}
fn bing_search() -> impl Stream<Item = String, Error = ()> {
let results = (0..10).map(|x| format!("bing{}", x));
let results = stream::iter_ok(results);
// Fake some delay between results
let delay = Interval::new_interval(Duration::from_millis(200));
results.zip(delay).map(|(r, _)| r).map_err(drop)
}
Этот вызов tokio::run
подразумевается в каждой программе Go; это запускает асинхронный реактор и запускает его "до завершения".