返回列表 发帖
本帖最后由 CrLf 于 2012-11-12 18:43 编辑

回复 8# qzwqzw


赞同“用固定的环境变量来做子函数返回值”,不太赞同“使用子函数的标签名作为返回值变量名”,cmd 中的变量读取效率如此蛋疼,还是能减少尽量少吧,而且应该使用在变量表中次序靠后的变量名,甚至用 %cmdcmdline% 都可以
-----------------------------------------------------------
如果“返回变量名为第一个实参名”
那么子函数在处理不定个数的参数数组时就会碰到麻烦

有点鱼与熊掌的味道,这看法我很赞同,但有时返回值不止一个就很头疼了
-----------------------------------------------------------
子函数内的环境变量是否除了返回值变量全部setlocal

窃以为这是在子函数需要产生临时变量时必须的,对全局变量的操作通过其他方法另行转存(除非变量中含换行符,否则应该能处理所有情况)
-----------------------------------------------------------
子函数内发生错误是否统一抛出处理?错误抛出后是在子程序中终止退出还是在主程序中?

另,建议返回值也以环境变量形式存在,即类似 bat_err 之类的变量名(最好还能短一点?比如 _err ?观察比较各种字符,似乎 _ 在表中名次比较靠后)
-----------------------------------------------------------
子函数内是否需要一个指示程序自身路径的变量%0%,以解决用%0递归调用自身时的问题

不赞同,首先以数字开头的变量名就是大忌,必须要用变量延迟才能避免错误解析,其次我实在想不到一个子函数在什么情况非得递归父脚本?

TOP

本帖最后由 CrLf 于 2012-11-13 18:25 编辑

回复 11# qzwqzw


    十分赞同 qzw 对于多返回参数使用指针指向类数组的观点,一直没想到用在这里,确实是个好办法!不过这是否说明我们也许要另外构造一些专门针对类数组的函数?比如清空数组、数组排序、提取与条件匹配的数组等等?
---------------------------------------------------
    不太明白老兄对于递归的意图和顾虑,在子函数中无论何时都可以通过 %0 获取当前函数名、用 %~f0 获取父脚本完整路径(plp看这里~嘿嘿),莫非兄台担忧的是无法在函数的子函数中回调父函数?
---------------------------------------------------
   其实对于 exit /b 我一直有比较大的成见,因为效率太低了,但无奈的是只有他能在函数中任意改变 errorlevel...执保留意见

TOP

回复 13# plp626


    如果要对父函数递归,那么自然有可能出现某个函数调用子函数后再调用父函数甚至父函数的父函数的特殊情况,这样岂不是要像堆栈一样累加保存每一层的函数名?否则如何保证函数互相调用的过程中总是能知道谁是父函数?
    虽说有时确实需要递归,但函数之间的关联太紧密总是违背编程惯例的。题外话,如果非要调用其他函数,那我觉得必须声明与哪些函数具有依赖性。
------------------------------------------------
    学习 htm dom 的过程中我深深地感受到,非必要情况下函数中对全局变量进行修改实在不利于脚本的维护,所以还是 setlocal 和 endlocal 较好,或者用约定的特殊前缀来定义函数内的变量,父脚本避免定义此类变量,仅在函数中使用,退出前还要将其清空以保证变量表是干净的
------------------------------------------------
    goto :eof 和 exit/b 相比,我觉得无论是效率还是功能都完全处于劣势,个人认为,最好的方案还是使用外置函数,一来不需要花费逐行寻找标签的时间,二来运行到文件末尾时自然会结束函数。

TOP

回复 16# plp626


    只需要按一定的格式声明只能从哪些父函数调用、函数中需要调用到哪些子函数(不考虑间接调用)、引用时是否需要和特定函数按照前后顺序排布就可以了,否则不是很容易在不知情的时候因为勿删具有依赖关系的函数而致错吗?

TOP

回复 18# plp626


    只需要声明下级函数就够了,不管更细的分支。如果这个声明的格式足够统一,那么完整的拓扑结构其实可以另外写个独立的脚本来分析

TOP

回复 20# qzwqzw


   
另外由于递归带来的另一问题是setlocal的层级限制
所以如果是支持递归的函数
建议不使用setlocal

每次 call 都是独享 32 张表空间的,所以不必担心递归时会超过 setlocal 上限,以前测试时写的一个 内存杀手.bat:
@echo off
%1 start /b cmd /v /c %0 :&exit/b
::启动一个新的 cmd 打开变量延迟而避免使用 setlocal,并关闭自身
for /f "delims==" %%a in ('set') do set %%a=
set f=for /l %%a in (9 -1)do
%f:9=7% %f:a=b% %f:a=c% %f:a=d% set @%%a%%b%%c%%d=@@@@@@@@@@@@@@@@@@@@@%%a%%b%%c%%d
for /l %%a in (8000 1 8191) do set @%%a=@@@@@@@@@@@@@@@@@@@@@%%a
rem 设置一大堆的变量,总量为 8192*32 字节
:test
set /a f+=1
(set /a f+=31
for /l %%a in (%f% 1 !f!) do (
echo %%a
setlocal
rem 不断 setlocal 开辟新的变量表
))
pause
call :test
::每次 call 都拥有独立的内存空间,所以又可以执行 32setlocal...COPY

TOP

本帖最后由 CrLf 于 2012-11-14 16:42 编辑

回复 13# plp626


    我的习惯是中途不改写,到结束脚本时再统一改写,多变量转存也许可临时定义含有 for 嵌套的变量型函数,有构思,回家试。另,昨天没理解老兄说的一去不返,今天才有点明白,莫非exit/b会同时退出所有子函数?还有,现在想来,调用外部函数时,%~f0是否还能获取父脚本名?手机无法测试,求验证
————————————
我构想中对函数依赖的声明是作为固定格式的注释写给使用者参考的,并不需要实际执行
————————————
函数内部的标签若要标准化将面临标签长度的限制,在8个字符长度的局限下如何同时保证可识别性和唯一性?

TOP

本帖最后由 CrLf 于 2012-11-14 18:52 编辑

回复 23# qzwqzw


    个人认为对于内嵌在脚本中的函数,所有东西都放进去实在有点冗杂,函数的参数接口和版本即可,具体说明在独立的使用范例脚本中注明较好。
但这样一来,内嵌函数与外置函数岂不是要使用两套标准?

TOP

本帖最后由 CrLf 于 2012-11-16 22:21 编辑

在 endlocal 后保留变量的构思,除了含换行符的变量外应该均可兼容
@echo off&setlocal enabledelayedexpansion
set a=123
set b=abc
set c=@#$
set "getEndlocal=endlocal"
for %%a in (a b c) do (
set "getEndlocal=(for /f "delims=" %%$ in (^!%%a^!)do !getEndlocal!&set "$_%%~a=%%$")"
)
echo 实际命令:
echo !getEndlocal!
echo;
%getEndlocal%
echo 执行后的效果:
set $_
pauseCOPY
如果写成函数就是这样(格式先随便写啦,仅作示例,回头再配合标准改写):
:getEndlocal varName [varName [varName [...]]]     Ver:0.1  By:bathome-Crlf
setlocal enabledelayedexpansion&set "$=endlocal"
for %%a in (%*) do set "$=(for %%$ in (^!%%a^!)do !$!&set "$_%%~a=%%$")"
for /f "delims=" %%a in ("!$!") do endlocal&set "getEndlocal=%%a"
::getEndlocal函数结束COPY

TOP

本帖最后由 CrLf 于 2012-11-15 22:32 编辑

对于伪数组的构思,仅作简单示例:
@echo off&setlocal enabledelayedexpansion
call :setAr 1234 @#$ test
echo2个元素 ar[1] = %ar[1]%
echo;
echo 最大上标 UB[ar] = %UB[ar]%
echo;
echo 显示“数组”中的所有元素
call :listAr ar
echo;
pause
:setAr
set UB[ar]=-1
for %%a in (%*) do (
set /a UB[ar]+=1
set "ar[!UB[ar]!]=%%a"
)
exit/b
:listAr
for /l %%a in (0 1 !UB[%1]!) do echo;!ar[%%a]!COPY
当然可以不定义 UB[arName],但是遍历数组时将很难兼顾通用性和效率

TOP

回复 31# qzwqzw


    我的目的是通用性最大化,常见的方案大思路主要有 set var=%var% 和 set var=%%a 两类,但前者的通用性实在是...
1、
endlocal&set var1=%var1%&set var2=%var2%
rem 若含 " 等将极易致错COPY
2、
for %%a in ($ "!var1=!var1!" "var2=!var2!") do (
   if %%a==$ (endlocal) else set "%%a"
)
rem 遇到变量内容含 * 和 ? 则必死无疑COPY
3、
set 换行符=^
for /f "delims=" %%a in ("$!换行符!var1=!var1!!换行符!var2=!var2!") do (
   if %%a==$ (endlocal) else set "%%a"
)
rem 个人认为比较好的方案1,但是获取换行符的那三行不容压缩和添字,难保 copy 的时候会不会出岔子(尤其是有些论坛经常会在行末添加空格)COPY
4、
for /f "delims=" %%a in ("var1=!var1!") do (
   for /f "delims=" %%b in ("var2=!var2!") do (
      endlocal
      set "%%b"
   )
   set "%%a"
)
rem 个人认为比较好的方案2,实际上我更喜欢方案3,但这个容易看懂,行数也可以压缩得很短COPY

TOP

话说 endlocal 后保留变量面临一个很郁闷的问题,如果用户在调用函数之前已经开启了变量延迟,而需要保留的变量内容中又含 ! 号,如何避免它被解释掉?难道输出到临时文件再 set /p?可是不用 setlocal 又难保变量环境的干净——尤其是函数间互相调用的时候

TOP

实在没办法的话,为了兼顾可读性和兼容性最大化,只好用临时文件了
set>"%tmp%\var.$"&endlocal
for /f "eol==delims=" %%a in ("%tmp%\var.$") do set "%%a"
del "%tmp%\var.$"COPY

TOP

返回列表