如果您还没有阅读范围,您可能应该阅读本教程。
范围何时会被消耗和不会被消耗取决于它的类型。如果它是输入范围而不是前向范围(例如,如果它是某种类型的输入流 -std.stdio.byLine
就是一个例子),那么以任何形状或形式对其进行迭代都会消耗它。
//Will consume
auto result = find(inRange, needle);
//Will consume
foreach(e; inRange) {}
如果它是一个前向范围并且它是一个引用类型,那么它会在你迭代它时被消耗,但是你可以调用save
来获取它的副本,并且消耗副本不会消耗原始的(也不会消耗原始消耗副本)。
//Will consume
auto result = find(refRange, needle);
//Will consume
foreach(e; refRange) {}
//Won't consume
auto result = find(refRange.save, needle);
//Won't consume
foreach(e; refRange.save) {}
事情变得更有趣的是作为值类型(或数组)的前向范围。它们的作用与 的任何前向范围相同save
,但它们的不同之处在于简单地将它们传递给函数或在foreach
隐式save
s 中使用它们。
//Won't consume
auto result = find(valRange, needle);
//Won't consume
foreach(e; valRange) {}
//Won't consume
auto result = find(valRange.save, needle);
//Won't consume
foreach(e; valRange.save) {}
因此,如果您处理的输入范围不是前向范围,则无论如何都会消耗它。如果你正在处理一个前向范围,save
如果你想保证它没有被消耗,你需要调用 - 否则它是否被消耗取决于它的类型。
关于ref
,如果你声明一个基于范围的函数来接受它的参数ref
,那么它不会被复制,所以传入的范围是否是引用类型并不重要,但这确实意味着你不能传递一个右值,这真的很烦人,所以你可能不应该ref
在范围参数上使用,除非你真的需要它来总是改变原始值(例如std.range.popFrontN
,需要 aref
因为它显式地改变原始值而不是潜在地操作 a复制)。
至于使用前向范围调用基于范围的函数,值类型范围最有可能正常工作,因为经常使用值类型范围编写和测试代码,而不总是使用引用类型正确测试。不幸的是,这包括了 Phobos 的功能(尽管这将得到修复;它只是尚未在所有情况下都经过适当的测试 - 如果您遇到任何情况下 Phobos 功能在引用类型前向范围内无法正常工作,请报告)。因此,引用类型前向范围并不总是按应有的方式工作。