函式副作用

函式副作用

函式副作用是指函式在正常工作任务之外对外部环境所施加的影响。具体地说,函式副作用是指函式被调用,完成了函式既定的计算任务,但同时因为访问了外部数据,尤其是因为对外部数据进行了写操作,从而一定程度地改变了系统环境。函式的副作用也有可能是发生在函式运行期间,由于对外部数据的改变,导致了同步运行的外部函式受到影响。

    • 中文名:函式副作用
    • 外文名:side effect of function
    • 发生时间:函式运行期间或调用时间
    • 危害:降低程式可读性等
    • 防止方法:将相关数据封装在独立的数据类型
    • 学科:计算机科学

简述

所谓函式副作用是指,当调用函式时,被调用函式除了返回函式值之外,还对主调用函式产生附加的影响。例如,调用函式时在被调用函式内部:

·修改全局量的值;

·修改主调用函式中声明的变数的值(一般通过指针参数实现)。

函式副作用会给程式设计带来不必要的麻烦,给程式带来十分难以查找的错误,并且降低程式的可读性。例如,由于双目运算的两个运算分量的计算次序不同,而带来运算结果不同,就是由函式副作用引起的。对函式副作用的看法与对GOTO语句的看法一样,在程式设计语言界一直有分歧,有人主张保留,有人主张取消。探测认为,可以保留函式副作用,但是应该限制程式设计师儘量不要使用函式副作用。由于函式副作用的影响,会产生以下问题。

·会使双目运算的结果依赖于两个运算分量的计算次序;

·还可能使某些在数学上明显成立的事实,在程式中就不一定成立。

表现

从语言的函式设计可以看到,函式能够无条件访问全局数据(包括全局变数、全局数组、全局静态数据),通过指针或引用参数访问主调函式的栈数据或者属于程式整体的堆数据,甚至系统全局堆数据。函式副作用正是通过函式访问这些数据所表现出来的。

1、良性副作用

通过指针或引用参数设计的函式,都具有访问外部数据的倾向。或许可以利用某个函式对外部数据的修改,简化或免于后续计算的工作。例如:

//=================//X0814.cpp//函式副作用(模拟库函式gets)//==========#includeusingnamespacestd;//----------------intlen;//串长//----------------char*getStr(char*s){len=0;while(cin>s[Len]&&s[len])len++;returnS;}//----------------intmain(){chara[100]jcout<=0;i--)//输出逆反串得益于变数lencout<

设计该getStr函式时,以获取C串为目标,但需要在循环输入字元中使用下标计数变数。将下标变数len有意设计成全局数据后,该变数正好可以用于之后的字串处理。

如果没有这个副作用的没计,后续输出逆反字串的工作,需要再次计算字串的长度。

当然,为了保证反覆调用的正确性,在开始输入字元时应预先初始化变数len。因为访问了全局变数Ien,所以,函式getStr只能局限于本程式。在设计时,需要注意其他函式是否有修改变数len的行为,以保证len值的时效性。

2、恶性副作用

记忆体泄漏是一种典型的函式恶性副作用。例如,输入n(参数)个整数,计算其中有几个逆序的函式:

intcntInvertion(intn){int*p=newint[n];for(inti=0;i>p[i];intcnt=0;for(intj=0;jp[k])cnt++;returncnt;}

该函式对于整数参数n,申请了堆空间来保存输入数据,并进行逆序计算。这本身无可非议,但因为在函式运行结束时没有返还堆记忆体,就使得运行环境发生了改变。

也许对紧接着的函式调用和数据访问没有明显的影响,但是由于占用了堆记忆体,减少了总的可用堆空间存量。如果有许多该函式的计算,随着一次次的调用,就会影响程式的正常运行,甚至影响整个计算机的正常运行。

预防

函式在运行期间,访问全局变数、全局数组、非静态数据、堆数据(通过指针和引用)、主调函式数据(通过指针或引用)都有可能产生一定程度的副作用。

有副作用的函式,其影响不一定会在直接的主调函式中反映出来,可能在多层调用中反映出来,或者递归结构,或者异常机制的处理结构等。

设计有副作用的函式,都是有目的的。

例如,通过指针和引用参数,主动让被调函式获得外部数据访问权,以便提高数据处理的性能。

例如,通过开闢全局数据,使得函式声明简单。

例如,通过返回指针或引用的做法,获得共享堆空间,以简化计算工作。

要利用函式副作用,首先应该明白副作用产生的原因,从而避开恶性副作用的产生。

函式副作用设计,还与程式设计方法有密切的关係。因为计算总也离不开数据,为了设计无副作用的函式,在对象化编程中,将相关数据儘量封装在独立的数据类型中,在该数据类型中去从事专门的数据操作。这样就避免了为了计算而让数据公开化、共享化,陷于不得不设计有副作用的函式的不利境地。

相关词条

相关搜索

其它词条