| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 906 人关注过本帖, 2 人收藏
标题:VFP学习、开发漫谈 (14)
只看楼主 加入收藏
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:658
专家分:2180
注 册:2014-2-7
结帖率:96.88%
收藏(2)
已结贴  问题点数:10 回复次数:5 
VFP学习、开发漫谈 (14)
今天,与大伙聊一聊有关自定义函数和过程问题。

在 VFP 中,程序以函数定义或以过程(子程序)定义,二者在功能上没有任何区别,区别仅在于其被调用的形式和参数的默认调用方式。这是我反复斟酌之后得出的结论,不知道高手们怎么看。

默认情况下(SET UDFPARMS TO VALUE,调用时不在变量前加 @、不将变量放在括号内),以函数方式调用时,参数采用传值方式;以过程方式调用(DO 过程 WITH 参数)时,参数采用传地址方式。

以自定义函数 UDF_PLUS(a,b) 为例:
    = UDF_PLUS(a,b)          && 以函数方式调用,参数 a,b 采用传值方式
    DO UDF_PLUS WITH a,b     && 以过程方式调用,参数 a,b 采用传地址方式

通过将参数放在括号内,强制采取传值方式调用:
    = UDF_PLUS((a),(b))
    DO UDF_PLUS WITH (a),(b)

通过在参数前加 @,强制采取传地址方式调用:
    = UDF_PlUS(@a,@b)
    DO UDF_PLUS WITH @a,@b

通过 Set UDFPARMS To Value/Refrence 命令,可以修改调用自定义函数时,参数的默认传递方式。注意:该设置不影响以过程方式,即 DO 命令方式调用函数。例如 :

    SET UDFPARMS TO VALUE
    = UDF_PLUS(a,b)          && 参数 a,b 采用传值方式
    DO UDF_PLUS WITH a,b     && 参数 a,b 仍然采用传地址方式
    SET UDFPARMS TO REFRENCE
    = UDF_PLUS(a,b)          && 参数 a,b 采用传地址方式
    DO UDF_PLUS WITH a,b     && 参数 a,b 采用传地址方式
   
从上面的例子可以看出:在采用过程方式调用函数时,若要求参数以传值方式调用,必须采用强制方式。即:DO UDF_Plus WITH (a),(b)
   
当过程/函数所接收的参数多于所需要的个数时,VFP 会报错。例如:函数仅定义了两个形参,调用时却指定了 3 个实参,如下所示:

    ? UDF_Plus(1,2,3)                    && 以 3 个实参调用函数,则报错
    FUNCTION UDF_PLUS(tnValue1,tnValue2) && 定义了 2 个形参
        RETURN tnValue1+tnValue2
    ENDFUNC

但如果过程/函数接收的参数个数少于所需要的数目,则 VFP 仅将余下的参数赋初值 .F.,而不报错。如下所示:

    ? UDF_PLUS(1)                        && 以 1 个实参调用函数,不报错
    FUNCTION UDF_PLUS(tnValue1,tnValue2) && 定义了 2 个形参
        *……
    ENDFUNC

在上面的实例中,调用函数时仅指定了第 1 个参数,也可以仅指定第 2 个参数,如:? UDF_PLUS( ,1)

需要指出的是:使用 DO 命令调用函数或过程时,无法获取返回值,而使用函数方式调用时,既可以获取返回值,如:nRet=UDF_Plus(1,2),也可以仅执行函数或过程的代码而忽略返回值,如:= UDF_Plus(1,2)。因此,以函数方式调用子程序或函数更加灵活。我在开发应用程序时,所有函数或过程均使用 FUNCTION 来定义,同时均使用函数方式来调用。

在自定义函数中,使用 RETURN 命令来返回结果值。若没有 RETURN 语句,则函数自动返回 .t.

自定义函数仅能返回一个值。如果函数要返回多个值,该怎么办呢?在实际应用中,我主要采用以下两种方法。

第一种方法:将多个值组合成一个字符串,并返回该字符串。使用时,再将返回的字符串拆分开。这类似于对文件的压缩和解压缩。
程序代码:
LOCAL cRet,nPlus,nMinus
cRet = Math(1,2)    &&2 个数的“和”与“差”
nPlus = VAL(STREXTRACT(cRet,'[',']',1))    && 获取“和”
nMinus = VAL(STREXTRACT(cRet,'[',']',2))   && 获取“差”
? nPlus
? nMinus

FUNCTION Math(tnValue1,tnValue2)
    LOCAL nPlus,nMinus,cRet
    nPlus = tnValue1 + tnValue2
    nMinus = tnValue1 - tnValue2
    cRet = '['+TRAN(nPlus)+']['+TRAN(nMinus)+']'
    RETURN cRet
ENDFUNC

第二种方法:将要返回的多个值保存到变量中,并以传地址方式调用并返回。仍以上例来说明:
程序代码:
LOCAL nPlus,nMinus
= Math(1,2,@nPlus,@nMinus)    &&2 个数的“和”与“差”
? nPlus
? nMinus

FUNCTION Math(tnValue1,tnValue2,tnPlus,tnMinus)
    tnPlus = tnValue1 + tnValue2
    tnMinus = tnValue1 - tnValue2
ENDFUNC

当要返回多个值时,我更喜欢使用第二种方法。除了上述方法外,还可以采用全局变量或私有变量的方法,但从结构化编程的思路来说,每个函数都应该相对独立,其与外部程序的联系仅能通过参数来进行。因此,不建议采用该方法。

可以使用 PARAMETERS()返回过程或自定义函数的实参数目。这里的过程或自定义函数是指最近调用的过程/函数,并不是指当前过程/函数

请看表单初始化事件中的一个错误:
程序代码:
LPARAMETERS tcPara
IF CheckRight('cb_clmx') # ''  && 若当前用户无写权限,禁用修改按钮
    THIS.cmdOK.Enabled = .f.
ENDIF
IF PARAMETERS() > 0              && 有参数传递时,定位记录
    THIS.Locate(tcPara)
ENDIF

当不传递参数调用表单时,tcPara=.f.,若在 Init 事件的第 2 行调用 PARAMETERS()则返回 0。但程序接着调用了 CheckRight(),此时 PARAMETERS()将返回 CheckRight()中的实参个数 1,导致语句 THIS.Locate(tcPara) 被执行,因而出错。

改正如下:
程序代码:
LPARAMETERS tcPara
IF PARAMETERS() > 0
    THIS.Locate(tcPara)
ENDIF
IF CheckRight('cb_clmx') # ''
    THIS.cmdOK.Enabled = .f.
ENDIF

或:
程序代码:
LPARAMETERS tcPara
IF CheckRight('cb_clmx') # ''
    THIS.cmdOK.Enabled = .f.
ENDIF
IF VARTYPE(tcPara) = 'C'
    THIS.Locate(tcPara)
ENDIF



[ 本帖最后由 liuxingang28 于 2014-4-4 08:16 编辑 ]
搜索更多相关主题的帖子: 子程序 开发 
2014-03-31 11:01
wp231957
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:神界
等 级:贵宾
威 望:423
帖 子:13688
专家分:53332
注 册:2012-10-18
收藏
得分:0 
vfp也能传址啊

DO IT YOURSELF !
2014-03-31 11:28
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
收藏
得分:0 
怎么不能
2014-03-31 11:35
wasun2012
Rank: 2
等 级:论坛游民
帖 子:12
专家分:17
注 册:2012-11-17
收藏
得分:10 
函数返回多个值
楼主善于总结,乐于分享,感谢... 楼主提到的调用函数返回多个值的第2种方法让我开了眼界,这个方法在调用API函数时会用到,但我没想过用在VFP的函数调用上. 但如果要返回的值的数目不定时,咋办呢? 所以我一般使用集合对象返回
2014-04-02 14:42
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:658
专家分:2180
注 册:2014-2-7
收藏
得分:0 
以下是引用wasun2012在2014-4-2 14:42:13的发言:

楼主善于总结,乐于分享,感谢... 楼主提到的调用函数返回多个值的第2种方法让我开了眼界,这个方法在调用API函数时会用到,但我没想过用在VFP的函数调用上. 但如果要返回的值的数目不定时,咋办呢? 所以我一般使用集合对象返回
如果事先无法确定返回值的数目,还可以通过数组来保存返回值。举例如下:
程序代码:
LOCAL aRet[1],oElement       && 定义一个用于保存返回值的数组
= UDF_PLUS(1,2,@aRet)        && 调用自定义函数
FOR EACH oElement IN aRet    && 显示返回值
    ? oElement
NEXT

FUNCTION UDF_PLUS (tnValue1,tnValue2,taRet)
    LOCAL i
    * 返回“和”
    taRet[1] = tnValue1 + tnValue2
    * 返回“差”
    i = ALEN(taRet)+1
    DIMENSION taRet[i]
    taRet[i] = tnValue1 - tnValue2
    * 返回“积”
    i = ALEN(taRet)+1
    DIMENSION taRet[i]
    taRet[i] = tnValue1 * tnValue2
    * ……
ENDFUNC


[ 本帖最后由 liuxingang28 于 2014-4-2 19:59 编辑 ]

泉城飞狐
2014-04-02 19:57
ILoveVFD
Rank: 3Rank: 3
等 级:论坛游侠
威 望:3
帖 子:218
专家分:147
注 册:2015-5-2
收藏
得分:0 
学习了!
2015-05-02 12:43
快速回复:VFP学习、开发漫谈 (14)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017004 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved