假设我想查看迭代器的第五个项目,但我想保留所有项目。最好的方法是什么?有模块吗?我可能可以将一个函数组合在一起来创建一个新的迭代器,但我想知道它是否已经完成了?
我正在编写一个迭代映射中的条目的函数。我希望能够干净地处理迭代时从地图中添加或删除的项目,就像for k, v := range myMap { //...所做的那样,但我每次迭代只处理一个键/值对,所以我不能使用范围。我想要这样的东西:
func processItem(i iterator) bool {
k, v, ok := i.next()
if(!ok) {
return false
}
process(v)
return true
}
var m = make(map[string]widget)
// ...
i := makeIterator(m)
for processItem(i) {
// code which might add/remove item from m here
}
Run Code Online (Sandbox Code Playgroud)
我知道 range 使用 ' hiter' 结构体和关联函数(如 中定义src/runtime/hashmap.go)来执行迭代。有没有什么方法可以访问这个迭代器作为一个具体化的(一流的)Go 对象?
是否有另一种迭代映射的策略可以很好地处理插入/删除,但提供一流的迭代器对象?
额外问题:是否有另一种迭代映射的策略,该策略还可以处理映射和迭代器被序列化到磁盘然后恢复的情况,迭代从停止的地方继续?(显然内置迭代range器不具备这个能力!)
在 PHP 7.1 中,有一个新的可迭代伪类型,它抽象数组和Traversable对象。
假设在我的代码中我有一个如下所示的类:
class Foo
{
private $iterable;
public function __construct(iterable $iterable)
{
$this->iterable = $iterable;
}
public function firstMethod()
{
foreach ($this->iterable as $item) {...}
}
public function secondMethod()
{
foreach ($this->iterable as $item) {...}
}
}
Run Code Online (Sandbox Code Playgroud)
$iterable这在is 数组或 an时工作得很好Iterator,除非$iterable是 a Generator。事实上,在这种情况下,调用firstMethod()thensecondMethod()将产生以下结果Exception: Cannot traverse an already closed generator。
有办法避免这个问题吗?
在 TypeScript (3.6.3) Generator<>中几乎与IterableIterator<>相同。当Generator<>扩展Iterator<> 时,它默认第三个泛型参数(TNext)为unknown。Iterator<>本身默认TNext为undefined。所以Generator和Iterator(以及IterableIterator)并没有像他们应该的那样排列。
let gen2:IterableIterator<string>;
function* gen1():Generator<string> {
yield* gen2;
}
Run Code Online (Sandbox Code Playgroud)
yield* 行是一个错误:“无法将迭代委托给 value,因为其迭代器的 'next' 方法期望类型为 'undefined',但包含的生成器将始终发送 'unknown'.ts(2766)”。
我错过了什么吗?这有充分的理由吗?
我已经听说std::vector<T>::iterator可以简单地T*代替迭代器类。
但这真的合法吗?
指针算术仅适用于数组,std::vector不创建数组对象 ( T[]) 而是创建连续对象(通过放置 new)。
此外,我认为std::launder甚至需要(C++17)来访问单个元素(正如我们可以在 的static_vector示例注释中阅读的那样std::aligned_storage)。
我认为这大致相当于遵循我认为是未定义的行为。
template <typename T, std::size_t N, typename F>
void test_array(F func)
typename std::aligned_storage<sizeof (T) * N, alignof (T)>::type data;
char* buffer = &data;
for (std::size_t i = 0; i != N; ++i) {
new (buffer + i * sizeof(T)) T;
}
T* array = reinterpret_cast<T*>(buffer);
for (std::size_t i = 0; i != N; …Run Code Online (Sandbox Code Playgroud) 我们有一个 HashMap,我们对其进行迭代和映射以替换值,但是遇到了一个问题,将其收集回具有不同值类型的新 HashMap。
value of type `std::collections::HashMap<std::string::String, std::string::String>`
cannot be built from `std::iter::Iterator<Item=(&std::string::String, std::string::String)>`
Run Code Online (Sandbox Code Playgroud)
我们所做的基本上归结为:
let old: HashMap<String, Value> = some_origin();
let new: HashMap<String, String> = old.iter().map(|(key, value)| {
return (key, some_conversion(value));
}).collect();
Run Code Online (Sandbox Code Playgroud)
如果对两个迭代器进行压缩,例如在这种情况下压缩键,并且映射仅返回转换后的值,则也会返回相同的迭代器类型(并且不可收集)。
new = old.keys().into_iter().zip(old.iter().map(|(key, value)| some_conversion(value)).collect();
Run Code Online (Sandbox Code Playgroud) 我希望能够std::list通过打印其值来打印任何迭代器。我的初始代码如下所示:
template<typename T>
std::ostream& operator<<(std::ostream& os, const typename std::list<T>::const_iterator& x)
{
return os << "&" << *x;
}
Run Code Online (Sandbox Code Playgroud)
哪个不起作用,因为编译器无法确定参数T。然后我尝试使它在迭代器类型本身上通用,并iterator_traits用于将其限制为迭代器。
template<
typename It,
typename = typename std::iterator_traits<It>::value_type
>
std::ostream &operator<<(std::ostream &os, const It &x)
{
return os << "&" << *x;
}
Run Code Online (Sandbox Code Playgroud)
但是,当然,我得到了两个相互冲突的实现std::ostream << *const char,因为指针也是迭代器。如何将实现限制为std::list迭代器,以免发生冲突?
考虑一个大内存容器。在这个简单的例子中std::vector<int>:
std::vector v = { 0, 1, 2, 3, 4, 5 };
Run Code Online (Sandbox Code Playgroud)
std::span允许我创建一个轻量级的内存视图。现在我想简单地打印跨度:
template<typename T>
void print(std::span<T> span) {
std::cout << '[';
if (span.size())
std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));
std::cout << span.back() << "]\n";
}
int main() {
std::vector v = { 0, 1, 2, 3, 4, 5 };
print(std::span{ v });
}
Run Code Online (Sandbox Code Playgroud)
输出:
[0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
现在我想制作子集(这是std::span实际作为视图变得有用的地方)。我可以用迭代器来指定我的范围,并调用此构造函数(3)从std::span
template< class It, class End >
explicit(extent != std::dynamic_extent) …Run Code Online (Sandbox Code Playgroud) 我正在编写一系列马尔可夫链蒙特卡罗 (MCMC)算法,通过将此处在 C++ 中实现的 MCMC 算法转换为 Rust 来用作程序归纳系统的推理方法。
MCMC 的粗略动态是我们有一些过程可以在对象空间周围随机移动并生成它发现的对象流。随机性是必不可少的。此外,此流永远不会终止(尽管您可以停止从流中获取对象)。更复杂的 MCMC 形式可以定义为这个基本过程的组合。
我的问题:我如何惯用地翻译这些算法?更具体地说,我如何从 rustacean 的角度考虑这个问题?为工作带来哪些正确的工具/技术?
这是我考虑过的:
直接翻译似乎很尴尬,因为 C++ 代码大量使用回调,鉴于我对 Rust 的了解有限,这感觉很尴尬。这似乎更符合我读过的其他 Rust 代码,只是让用户可以懒惰地使用他们认为合适的样本流。
然后我认为迭代器可能有意义,但是:
&mut Rwhere R: Rng),并访问一个简单的控制结构来跟踪各种统计数据。将这些直接烘焙到任何结构实现中Iterator意味着我无法以共享控制结构或随机源的方式组合算法,对吗?生成器/协程似乎解决了这些问题,但似乎是一个相对边缘/生锈的新领域。我开始怀疑我是否让事情变得比他们需要的更难。
我目前为每个算法提供了一个类似于以下函数的结构,其中H是假设,C是控制结构:
impl<C, H> MCMCChain<C, H> {
// ...
pub fn next_sample<R: Rng>(&mut self, control: &mut C, rng: &mut R) -> Option<Self>
// ...
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,next_sample会回来Option<&H>,但这就是我现在正在做的事情。
我一直希望使用新的 C++17 功能,如折叠表达式,并std::apply()简化我使用的一些 C++11 代码,这些代码使用诸如std::index_sequence和 之类的工具std::initializer_list对元组进行某些操作。特别是一项任务给我带来了一些麻烦:将一系列值(例如从boost::tokenizer对象)复制到元组。我有一个工作解决方案,它调用std::apply()要为其分配值的元组,但仍必须在std::initializer_list内部使用(为简单起见,我用一个简单的向量替换了 boost 标记器迭代器:
#include <iostream>
#include <vector>
#include <tuple>
template<typename Tuple, typename Iterator>
size_t copy_range_to_tuple(Tuple& tup, Iterator begin, Iterator end) {
size_t count = 0;
auto copy = [&begin,&end,&count] (auto& value) -> bool {
if (begin != end) {
value = *(begin++);
++count;
return true;
} else {
return false;
}
};
std::apply([©](auto&... values) {
std::initializer_list<bool>{copy(values)...};
}, tup);
return count;
}
int main(int,char**) …Run Code Online (Sandbox Code Playgroud)