Rust中`impl`作为函数参数/返回类型的含义及代码实现问询
Q2: What does impl mean in this generator code, and how to replicate this in Rust/C++?
First, let's unpack the Rust code you shared:
pub fn up_to(limit: u64) -> impl Generator<Yield = u64, Return = u64> { move || { for x in 0..limit { yield x; } return limit; } }
The impl here
The impl Generator<Yield = u64, Return = u64> is exactly the return type case we covered earlier. The function returns a generator (created via the move || { ... yield ... } syntax), which is an anonymous, unnameable type. Using impl Generator lets us return this generator without having to expose its concrete type.
The Generator trait defines the generator's behavior: Yield is the type of values it produces with yield, and Return is the type of the value it returns when it finishes executing.
Pure Rust implementation (alternative with boxing)
Your original code is already a valid Rust implementation, but if you need dynamic dispatch (e.g., storing the generator in a trait object), you can use Box<dyn Generator> instead:
use std::ops::{Generator, GeneratorState}; use std::pin::Pin; pub fn up_to(limit: u64) -> Box<dyn Generator<Yield = u64, Return = u64>> { Box::new(move || { for x in 0..limit { yield x; } return limit; }) } // To use the generator: fn main() { let mut generator = Pin::new(up_to(5)); loop { match generator.as_mut().resume(()) { GeneratorState::Yielded(val) => println!("Yielded: {}", val), GeneratorState::Complete(ret) => { println!("Completed with: {}", ret); break; } } } }
Note: Generators need to be pinned (via Pin) because they hold internal state that can't be moved in memory once execution starts.
C++ implementation
C20 introduced coroutines, which let us replicate this generator behavior. For C23, the standard library includes std::generator which simplifies this. If you need to capture the final return value (like the Rust example), you'll need a custom coroutine type since std::generator focuses on iterating yielded values.
C++23 with std::generator (for yielded values)
#include <generator> #include <iostream> std::generator<unsigned long long> up_to(unsigned long long limit) { for (unsigned long long x = 0; x < limit; ++x) { co_yield x; } // std::generator doesn't expose co_return values directly—use the custom version below if you need this } int main() { for (auto val : up_to(5)) { std::cout << "Yielded: " << val << '\n'; } }
Custom C++ coroutine (with return value)
#include <coroutine> #include <optional> #include <iostream> // Custom coroutine type to handle both yielded values and a final return struct GeneratorWithReturn { struct promise_type { unsigned long long return_val; std::optional<unsigned long long> yielded_val; GeneratorWithReturn get_return_object() { return GeneratorWithReturn{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() { std::terminate(); } std::suspend_always yield_value(unsigned long long val) { yielded_val = val; return {}; } void return_value(unsigned long long val) { return_val = val; } }; std::coroutine_handle<promise_type> handle; ~GeneratorWithReturn() { if (handle) handle.destroy(); } GeneratorWithReturn(GeneratorWithReturn&& other) : handle(other.handle) { other.handle = nullptr; } GeneratorWithReturn& operator=(GeneratorWithReturn&& other) { if (handle) handle.destroy(); handle = other.handle; other.handle = nullptr; return *this; } // Get next yielded value, or std::nullopt if done std::optional<unsigned long long> next() { handle.resume(); if (handle.done()) return std::nullopt; auto val = handle.promise().yielded_val; handle.promise().yielded_val = std::nullopt; return val; } // Get the final return value after the generator completes unsigned long long get_return() const { return handle.promise().return_val; } }; GeneratorWithReturn up_to_with_return(unsigned long long limit) { for (unsigned long long x = 0; x < limit; ++x) { co_yield x; } co_return limit; } int main() { auto gen = up_to_with_return(5); while (auto val = gen.next()) { std::cout << "Yielded: " << *val << '\n'; } std::cout << "Completed with: " << gen.get_return() << '\n'; }
内容的提问来源于stack exchange,提问作者Sandeep Datta

