[英]Is it possible to return a `Keys<'_, K, V>` iterator as an more generic iterator of `&K`?
I would to write a method that returns self.hash_map.keys()
while hiding from the caller the concrete type Keys<'_, K, V>
.我会编写一个返回
self.hash_map.keys()
的方法,同时向调用者隐藏具体类型Keys<'_, K, V>
。
A downside of the Keys
return type is that it exposes to the caller that the K
elements are coming from a HashMap. Keys
返回类型的一个缺点是它向调用者公开K
元素来自 HashMap。 Intuitively, it seems as though it shouldn't be necessary to expose this information.直觉上,似乎没有必要公开这些信息。
Both of the options you speculated about are possible.您推测的两个选项都是可能的。
The simplest option is to use the impl
type syntax, which is an “existential” type: “I am going to return a value which implements Iterator
but I'm not telling you what the concrete type is”.最简单的选择是使用
impl
类型语法,它是一种“存在”类型:“我将返回一个实现Iterator
的值,但我不会告诉你具体类型是什么”。 In this case, the compiler knows what the type is (so the compiled code is exactly the same as if it wasn't hidden), but the user of your method cannot rely on anything but the specified trait, so you aren't leaking implementation details.在这种情况下,编译器知道类型是什么(因此编译后的代码与未隐藏时完全相同),但您的方法的用户只能依赖指定的特征,因此您不会泄漏实施细节。
impl MyType {
fn keys(&self) -> impl Iterator<Item = &MyKeyType> {
self.hash_map.keys()
}
}
(Note that this resembles but is not the same as dyn Iterator
; when you use dyn
, you're using runtime dispatch and the same function can return different concrete types from different calls to it. With impl
, the type is static, just hidden, and there is no overhead.) (请注意,这与
dyn Iterator
相似但不同;当您使用dyn
时,您正在使用运行时调度,并且相同的 function 可以从不同的调用返回不同的具体类型。使用impl
,类型是 static,只是隐藏,并且没有开销。)
The disadvantage of this option is that the type is entirely unnameable;此选项的缺点是类型完全无法命名; for example, nobody can write a structure that holds your
keys()
iterator except by making it generic over all Iterator
s.例如,没有人可以编写一个包含您的
keys()
迭代器的结构,除非将其设为对所有Iterator
的通用。 (This is rarely a problem for iterators in particular, since iterator wrappers are usually generic anyway.) (这对于迭代器来说很少是个问题,因为迭代器包装器通常是通用的。)
Also, if your iterator implements any additional traits you want to allow the caller to use, like Debug
or ExactSizeIterator
, then you need to add them to the impl
type or they won't be visible.此外,如果您的迭代器实现了您希望允许调用者使用的任何其他特征,例如
Debug
或ExactSizeIterator
,那么您需要将它们添加到impl
类型中,否则它们将不可见。
Another option is to wrap the iterator in your own struct.另一种选择是将迭代器包装在您自己的结构中。 This allows you to hide the implementation type while still allowing callers to refer to it by name, so it's the most flexible.
这允许您隐藏实现类型,同时仍允许调用者按名称引用它,因此它是最灵活的。 The disadvantage of this option is that you have to explicitly implement
Iterator
(and any other traits) for the wrapper:此选项的缺点是您必须为包装器显式实现
Iterator
(和任何其他特征):
impl MyType {
fn keys(&self) -> MyKeyIterator<'_> {
MyKeyIterator(self.hash_map.keys())
}
}
#[derive(Clone, Debug)]
struct MyKeyIterator<'a>(Keys<'a, MyKeyType, MyValueType>);
impl<'a> Iterator for MyKeyIterator<'a> {
type Item = &'a MyKeyType;
fn next(&mut self) -> Option<&'a MyKeyType> {
self.0.next()
}
}
Rust Playground link with supporting code Rust 游乐场链接带支持代码
This wrapper should not add any performance cost (when compiled with optimization), except that by default the wrapper method will not be inlined if called from another crate.这个包装器不应该增加任何性能成本(当使用优化编译时),除了默认情况下如果从另一个箱子调用包装器方法将不会被内联。 If you're writing a library and this method is performance-sensitive, you can either enable link-time optimization (LTO) in the build, or add
#[inline]
to the next
method (which enables cross-crate inlining).如果您正在编写库并且此方法对性能敏感,您可以在构建中启用链接时优化 (LTO),或将
#[inline]
添加到next
方法(启用跨箱内联)。 Of course, don't do any such tweaking without checking whether it makes a difference to actual performance;当然,不要在不检查它是否对实际性能产生影响的情况下进行任何此类调整; otherwise you're just increasing compile time (and instruction cache thrashing).
否则你只是增加编译时间(和指令缓存抖动)。
Can it be accomplished by some precise choice of return type?
可以通过一些精确的返回类型选择来完成吗? Is some form of type-erasure possible?
某种形式的类型擦除可能吗?
Yes!是的! You can return an
impl Trait
to indicate that you're returning a type that implements Trait
but doesn't expose the concrete type:您可以返回一个
impl Trait
以表明您正在返回一个实现Trait
但不公开具体类型的类型:
fn keys(&self) -> impl Iterator<Item = &K> {
self.hash_map.keys()
}
See it working on the playground .看到它在操场上工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.