这个纯函数如何能够修改非私有状态?
TDPL,p。 167:
只要函数中的可变状态完全是瞬态(即,在堆栈上分配)和私有(即,不通过引用传递给以下函数)可能会污染它),那么该函数可以被认为是纯函数。
import std.stdio : writeln;
struct M{
int[4] _data;
pure ref int opIndex(size_t i){ return _data[i]; }
}
pure M foo(ref M m){
m[0] = 1234;
return m;
}
void main(){
M m1 = M([7, 7, 7, 7]);
writeln(m1);
foo(m1);
writeln(m1);
}
// output:
// M([7, 7, 7, 7])
// M([1234, 7, 7, 7])
可变状态是暂时的,因为它位于堆栈上,对吗?但这不是私人的。那么 foo()
如何允许修改 m1
呢?
TDPL, p. 167:
as long as the mutable state in a function is entirely transitory (i.e., allocated on the stack) and private (i.e., not passed along by reference to functions that may taint it), then the function can be considered pure.
import std.stdio : writeln;
struct M{
int[4] _data;
pure ref int opIndex(size_t i){ return _data[i]; }
}
pure M foo(ref M m){
m[0] = 1234;
return m;
}
void main(){
M m1 = M([7, 7, 7, 7]);
writeln(m1);
foo(m1);
writeln(m1);
}
// output:
// M([7, 7, 7, 7])
// M([1234, 7, 7, 7])
The mutable state is transitory because it's on the stack, correct? But it's not private. So how is foo()
allowed to modify m1
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
自 TDPL 发布以来,
pure
已经得到了一些扩展,因为 TDPL 所描述的pure
被证明限制性太大,除了简单的数学函数等之外没有什么用处。您可以查看在线文档了解当前的定义,但它本质上可以归结为:纯
函数不能访问任何在程序运行过程中可能发生变化的模块级或静态变量(它们必须是const
值类型或不可变
)代码> 可以从pure
函数)。pure
函数无法调用任何非pure
的函数。pure
函数无法执行 I/O。就是这样。没有其他限制。但是,如果要优化
pure
函数,使其仅被调用一次,即使它在一条语句中使用多次, 还需要额外的限制。即:不可变
或者可以隐式转换为不可变
。理论上,这可以扩展为要求函数的参数必须是不可变的或隐式转换为不可变的(以便具有
的函数const
参数在给定不可变
参数时可以进行优化),但目前情况并非如此。此类
纯
函数有时被称为“强”纯
,而那些无法优化的函数则被称为“弱”纯
。 TDPL 强烈描述了纯
函数。添加了弱pure
函数,以使pure
更通用。虽然弱
pure
函数可以改变它们的参数,但它们不能改变全局状态,所以当它们被强pure
函数(其中< em>不能改变它们的参数),对于相同的参数,强pure
函数的返回值始终相同的保证仍然成立。本质上,由于弱pure
函数无法改变全局状态,因此它们是调用它们的强pure
函数的私有状态的一部分。因此,它非常符合 Andrei 在第 5.11.1.1 节中描述的内容pure
与 TDPL 中的pure
的作用不同,除了私有状态该函数的功能已扩展为允许可以在不改变全局状态的情况下改变其私有状态的函数。自 TDPL 以来添加的关于
pure
的另一个重要事项是函数属性推断。pure
、nothrow
和@safe
是针对模板化函数进行推断的(尽管对于普通函数而言不是)。因此,如果模板化函数可以是纯
,那么现在它是纯
。它的纯度取决于它的实例化内容。因此,可以将pure
与模板化函数一起使用,而以前,您通常不能这样做,因为如果将其设为pure
,它就无法与不纯的函数一起使用功能。但是,如果您没有使其pure
,那么您就无法将其与pure
函数一起使用,所以这对于pure
来说是一个主要问题。幸运的是,属性推断现在解决了这个问题。只要模板化函数在实例化时遵循上面列出的规则,那么它就被认为是纯
。pure
has been expanded a bit since the release of TDPL, sincepure
as TDPL describes turns out to be far too restrictive to be useful beyond simple math functions and the like. You can look at the online documentation for the current definition, but it essentially comes down to this:pure
functions cannot access any module-level or static variables which can be mutated during the course of the program (they must beconst
value types orimmutable
to be accessed from apure
function).pure
functions cannot call any functions which are notpure
.pure
functions cannot perform I/O.That's it. There are no other restrictions. However, there are additional restrictions required if a
pure
function is going to be optimized such that it only gets called one time even if it's used multiple times within a statement. Namely:immutable
or implicitly convertible toimmutable
.In theory that could be expanded to requiring that the function's arguments must be
immutable
or implicitly convertible toimmutable
(so that a function withconst
parameters could be optimized when it's givenimmutable
arguments), but that's not currently the case.Such
pure
functions are sometimes referred to as "strongly"pure
, whereas those which cannot be optimized would be referred to as "weakly"pure
. TDPL describes stronglypure
functions. Weaklypure
functions were added in order to makepure
more generally usable.While weakly
pure
functions can alter their arguments, they cannot alter the global state, so when they're called by stronglypure
functions (which can't alter their arguments), the guarantee that the stronglypure
function's return value will always be the same for the same arguments still holds. Essentially, because the weaklypure
functions cannot mutate global state, they're part of the private state of the stronglypure
function that they're called from. So, it's very much in line with what Andrei describes in section 5.11.1.1pure
is aspure
Does in TDPL, except that the private state of the function has been expanded to allow functions which can alter its private state without altering global state.Another major thing of note which has been added since TDPL with regards to
pure
is function attribute inference.pure
,nothrow
, and@safe
are inferred for templated functions (though not for normal functions). So, if a templated function can bepure
, now it ispure
. Its purity depends on what it's instantiated with. So, it becomes possible to usepure
with templated functions, whereas before, you usually couldn't, because if you made itpure
, it wouldn't work with an impure function. But if you didn't make itpure
, then you couldn't use it with apure
function, so it was a major problem forpure
. Fortunately, attribute inference fixes that now though. As long as a templated function follows the rules listed above when it's instantiated, then it's consideredpure
.this
引用被视为函数参数的一部分,并且由于该函数是弱纯函数,因此您可以修改参数。当this
的状态被视为输入的一部分时,该函数仍然满足具有相同输入的相同输出的条件。考虑这个完全合法的例子,它输出
2
:据我所知,在 TDPL 发布后,pure 的定义得到了扩展。本书描述了强纯函数。之后,发生了两项发展:添加了弱纯函数,允许改变其参数。此外,还为模板函数添加了纯度推断,以便您可以使用模板函数的实例化,只要它是纯的,即使模板函数没有用
pure
修饰。The
this
reference is considered part of the function's parameters, and since the function is weakly pure, you can modify the parameters. With the state ofthis
considered part of the input, the function still fulfills the condition of having the same output with the same input.Consider this entirely legal example, which outputs
2
:As far as I know, after TDPL was released, the definition of pure was expanded. The book describes strongly-pure functions. After that, two developments have taken place: weakly-pure functions were added, which are allowed to mutate their parameters. Also, purity-inference has been added for template functions so that you can use a template function's instantiation as long as it's pure even if the template function isn't decorated with
pure
.