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

D 这个纯函数如何修改非私有状态?,d,pure-function,D,Pure Function,TDPL,p。167: 只要函数中的可变状态是完全临时的(即,在堆栈上分配)和私有的(即,不通过引用传递给可能污染它的函数),那么函数就可以被视为纯函数 可变状态是暂时的,因为它在堆栈上,对吗?但这不是私人的。那么如何允许foo()修改m1?此引用被视为函数参数的一部分,并且由于函数是弱纯函数,因此可以修改参数。当状态为时,该被视为输入的一部分,该函数仍然满足具有相同输入的相同输出的条件 考虑这个完全合法的例子,它输出2: import std.stdio : writeln; struct

TDPL,p。167:

只要函数中的可变状态是完全临时的(即,在堆栈上分配)和私有的(即,不通过引用传递给可能污染它的函数),那么函数就可以被视为纯函数


可变状态是暂时的,因为它在堆栈上,对吗?但这不是私人的。那么如何允许
foo()
修改
m1

引用被视为函数参数的一部分,并且由于函数是弱纯函数,因此可以修改参数。当状态为
时,该
被视为输入的一部分,该函数仍然满足具有相同输入的相同输出的条件

考虑这个完全合法的例子,它输出
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);
}

据我所知,在TDPL发布后,pure的定义得到了扩展。这本书描述了非常纯的函数。在此之后,出现了两个发展:添加了弱纯函数,允许它们改变参数。此外,还为模板函数添加了纯度推断,这样,即使模板函数没有用
pure

pure
修饰,只要模板函数是纯的,就可以使用它的实例化,因为TDPL描述的
限制性太强,除了简单的数学函数之类的函数外,没有什么用处。您可以查看当前的定义,但基本上可以归结为:

  • pure
    函数无法访问任何模块级或静态变量,这些变量在程序执行过程中可能会发生变化(它们必须是
    const
    值类型或
    不可变的
    才能从
    pure
    函数访问)

  • pure
    函数不能调用任何非
    pure
    函数

  • 功能无法执行I/O

  • 就这样。没有其他限制。但是,如果要优化
    函数,使其即使在语句中多次使用,也只能被调用一次,则需要额外的限制。即:

    • 函数的参数必须是
      不可变的
      或隐式转换为
      不可变的
    从理论上讲,这可以扩展到要求函数的参数必须是
    不可变的
    或隐式转换为
    不可变的
    (这样,当给定
    不可变的
    参数时,具有
    常量
    参数的函数可以得到优化),但目前情况并非如此

    这种
    pure
    函数有时被称为“强”
    pure
    ,而那些无法优化的函数则被称为“弱”
    pure
    。TDPL强烈地描述了
    函数。添加了弱
    pure
    函数,以使
    pure
    更通用

    虽然弱
    pure
    函数可以改变它们的参数,但它们不能改变全局状态,因此当它们被强
    pure
    函数调用(不能改变它们的参数)时,保证强
    pure
    函数的返回值对于相同的参数始终保持不变。本质上,因为弱
    pure
    函数不能改变全局状态,所以它们是从中调用的强
    pure
    函数的私有状态的一部分。因此,它与Andrei在第5.11.1.1节
    pure
    中描述的非常一致,就像TDPL中的
    pure
    一样,只是函数的私有状态已经扩展,允许函数在不改变全局状态的情况下改变其私有状态


    另一个自TDPL以来添加的关于
    pure
    的主要注意事项是函数属性推断<代码>纯
    无行
    @safe
    是为模板化函数推断的(但不是为正常函数)。因此,如果模板化函数可以是
    纯的
    ,那么现在它是
    纯的
    。它的纯度取决于它用什么实例化。因此,可以将
    pure
    与模板化函数一起使用,而以前,通常不能,因为如果将其设置为
    pure
    ,则无法与不纯函数一起使用。但是如果您没有使它成为纯的,那么您就不能将它与纯的函数一起使用,因此这是纯的一个主要问题。幸运的是,属性推理现在解决了这个问题。只要一个模板函数在实例化时遵循上面列出的规则,那么它就被认为是
    纯的

    我想我必须接受这种情况,并习惯于
    纯空opIndexAssign(T值,size_T I){…}
    纯T opIndex(size_T I)const{…}
    只需将
    pure
    看作是函数无法访问可变全局状态的意思,然后让编译器在可以的时候对其进行优化。是的,
    pure
    修饰符最终得到的函数比那些功能上的
    pure
    修饰符更多,但仍然是使功能上的
    pure
    函数成为可能并得以优化的原因。我一直在尝试清理标签,因为它有时指纯虚拟函数,有时是对的,有时是对的。但我对这件事一无所知。你能确认我的标签编辑是否合适吗?将适用于此问题-我创建了,因此如果有效,我认为最好使用现有标记。@RichardJPLeGuen Pure如中所示,因此Pure函数适用于此问题。纯粹是功能性的,没有那么多。。。虽然被列在维基百科页面的相关链接中。
    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);
    }