这个纯函数如何能够修改非私有状态?

Arl*_*len 5 d pure-function

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

Jon*_*vis 6

pure自TDPL发布以来,它已经有所扩展,因为pureTDPL描述的结果是限制太多而不能用于简单的数学函数之外.您可以查看当前定义的在线文档,但它基本上归结为:

  1. pure函数无法访问在程序过程中可以变异的任何模块级或静态变量(它们必须是const值类型或immutablepure函数访问).

  2. pure函数不能调用任何不是的函数pure.

  3. 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.


jA_*_*cOp 5

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.