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])
Run Code Online (Sandbox Code Playgroud)
可变状态是暂时的,因为它在堆栈上,对吗?但它不是私密的.那怎么foo()
允许修改m1
?
pure
自TDPL发布以来,它已经有所扩展,因为pure
TDPL描述的结果是限制太多而不能用于简单的数学函数之外.您可以查看当前定义的在线文档,但它基本上归结为:
pure
函数无法访问在程序过程中可以变异的任何模块级或静态变量(它们必须是const
值类型或immutable
从pure
函数访问).
pure
函数不能调用任何不是的函数pure
.
pure
函数无法执行I/O.
而已.没有其他限制.但是,有是如果需要额外的限制pure
功能将被优化,使得它只能被调用,即使它使用的语句中多次一次.即:
immutable
或可以隐式转换为immutable
.从理论上讲,可以扩展为要求函数的参数必须immutable
或可以隐式转换为immutable
(以便const
在给定immutable
参数时可以优化带参数的函数),但目前情况并非如此.
这些pure
功能有时被称为"强烈" pure
,而那些不能被优化的功能将被称为"弱" pure
.TDPL描述了强大的pure
功能.pure
添加了弱功能以便pure
更普遍地使用.
虽然弱pure
函数可以改变它们的参数,但是它们不能改变全局状态,所以当它们被强pure
函数调用(它们不能改变它们的参数)时,强pure
函数的返回值的保证将始终相同.争论仍然存在.本质上,因为弱pure
函数不能改变全局状态,所以它们是pure
它们被调用的强函数的私有状态的一部分.所以,它在什么安德烈介绍在第5.11.1.1非常符合pure
作为pure
是否在TDPL,除了功能的私有状态已扩大到允许它可以改变它的私有状态,而不会改变全局状态的功能.
自TDPL以来已经添加的另一个重要注意事项pure
是函数属性推断.pure
,nothrow
和@safe
,推断模板化函数(虽然不适用于普通函数).所以,如果一个模板函数可以是pure
,现在是 pure
.它的纯度取决于它的实例.因此,可以使用pure
模板化函数,而以前,你通常不能,因为如果你做了它pure
,它将不适用于不纯的函数.但是如果你没有成功pure
,那么你就无法使用它pure
,因此它是一个主要的问题pure
.幸运的是,属性推断现在修复了.只要模板化函数在实例化时遵循上面列出的规则,就会考虑它pure
.
该this
引用被认为是函数参数的一部分,由于该函数的纯度很弱,您可以修改参数.对于被this
认为是输入部分的状态,该功能仍然满足具有相同输入的相同输出的条件.
考虑这个完全合法的例子,它输出2
:
import std.stdio : writeln;
struct S
{
int foo = 0;
pure void set(size_t i){ foo = i; }
}
void main()
{
S s;
s.set(2);
writeln(s.foo);
}
Run Code Online (Sandbox Code Playgroud)
据我所知,在TDPL发布后,纯粹的定义得到了扩展.这本书描述了强大的纯函数.在那之后,发生了两个发展:添加了弱纯函数,允许改变它们的参数.此外,为模板函数添加了纯度推理,以便您可以使用模板函数的实例化,只要它是纯的,即使模板函数没有修饰pure
.