[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
本帖最后由 plp626 于 2012-11-14 01:00 编辑

回复 15# CrLf


    递归是迟早要考虑的,一大堆的脚本,互相调用,掉得多了,迟早会遇到有间接调用自己的时候。。

声明函数调用依赖这会使得问题很复杂, 你会充当人肉解释器的感觉。。。

----------------------
关于全局变量:
函数外部变量的修改在库函数实现中 需求强劲;

TOP

回复 16# plp626


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

TOP

a 调 b c;
b 调 d e;
c 调 b d a;

函数依赖关系不是树状的, 你会不自觉地陷入间接调用的情况,你要强制不能递归还得额外做些检测工作, 仅不能递归,我觉得就大大削弱库的功能,

一个的格式声明。。。,那么每个函数都会产生额外的解析语句,这一点你是否考虑过

TOP

回复 18# plp626


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

TOP

本帖最后由 qzwqzw 于 2012-11-14 17:45 编辑
是否说明我们也许要另外构造一些专门针对类数组的函数?

这个可以有,但未必是必须的,因为大多数场合下,我们只会对这个类数组进行简单的操作

不太明白老兄对于递归的意图和顾虑

这个你成功的说服了我,确实在函数内部定义引用宿主脚本的环境变量不是必须的
这个我是受了过去代码的思维定势了
%~f0的用法我以前见到过,只不过没有留下印象
现在我对它的印象是比较深刻了

exit /b 我一直有比较大的成见,因为效率太低了
call 脚本中遇到exit/b 退出就一去不返了

我认为exit /b可以用在抛出错误的特定场合
这种场合下“退出就一去不返”是需要的特性
而大多数的脚本错误抛出不会太多次
所以效率是不需要着重考虑的问题

goto :eof 和 exit/b 相比,我觉得无论是效率还是功能都完全处于劣势,个人认为,最好的方案还是使用外置函数,一来不需要花费逐行寻找标签的时间,二来运行到文件末尾时自然会结束函数。

goto :eof仍然应该是大多数函数结束自身的代码
一者是编程者的思维惯性
二者是与外置函数需要重新定位文件相比,它的效率未必低多少
况且goto :eof有着与goto :end不同的处理方式
效率未必会差到哪里

有时候你不得不需要在函数内部中途改写外部变量

这种场合我还没有遇到过
一般来说如果在函数内部改写了外部变量
那么至少在函数结束前这个改写都是有效的
只需要在函数结束前用endlocal&set
那么这个改写就持久化了
除非遇到函数内部以类exit的形式非正常结束
这个改写才是无效的
但如果将类exit的形式定义为只有发生错误才能使用
那么不改写反而符合正常的逻辑

干脆用高级语言的栈空间思想吧, 临时变量函数内部的变量都用栈来维护

栈的结构决定了存取时的复杂性
将这种复杂性普遍应用于整个库上是得不偿失的

14楼变量批量复制的实现不错

递归是迟早要考虑的,一大堆的脚本,互相调用,掉得多了,迟早会遇到有间接调用自己的时候

递归是少部分函数需要考虑的事情
另外凡是支持递归的函数都应该自己设置递归终结
我还看不出递归和声明函数调用依赖之间的关系

另外由于递归带来的另一问题是setlocal的层级限制
所以如果是支持递归的函数
建议不使用setlocal
或者在内部另使用一组标签来进行递归
这个与函数内部if...goto...形式的条件循环类似

由此带来另外一个问题
函数内部的标签命名是否需要标准化
以避免出现多个类似:loop/:menu/:end重复标签的情况发生
天的白色影子

TOP

回复 20# qzwqzw


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

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

TOP

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

回复 13# plp626


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

TOP

本帖最后由 qzwqzw 于 2012-11-14 17:55 编辑

setlocal的层级与call的关系是第一次听说
受教了

exit/b只会退出当前函数的call环境

“调用外部函数”要看用什么方式调用了
据我所知call lib :funciton的方式是无法让%~f0获取父脚本名的

标签长度的问题以前咱们讨论过,你大概忘记了
http://www.bathome.net/redirect. ... 5976&pid=104939

说起注释
我觉的这是一个标准化的重要内容
对于注释的形式、内容都应该有一定的规范
比如所有的函数库都必须通过注释注明
修订版本、更新日期、可运行环境 、遵循的接口标准
所有的函数都必须注明函数的用途、用法、已发现的限制等
天的白色影子

TOP

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

回复 23# qzwqzw


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

TOP

本帖最后由 Demon 于 2012-11-14 19:34 编辑

虽不明但绝厉。

TOP

本帖最后由 plp626 于 2012-11-14 23:44 编辑

经讨论,用固定环境变量名作为函数返回值这一想法, 优势大于劣势(可维护可读性可扩展性好)

现在讨论下这个返回变量名 名字的约定,我以前用过 $_,$, ##,.... 为了给它起个合理富有意义的名字改了好多次, 现在用的是$_ ,,大家讨论约定个标准。。。
-------------------------------------------
对于入口的参数, 也得有个约定,一个入口参数什么都好说,两个三个也好说,上了10个就不好搞了
而且不少时候,入口参数 兼有传入和传出两重身份

看看大家有什么好的方法。。。使得复杂问题能够简单化解决。。。

TOP

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

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

TOP

所谓内嵌和外置函数
你应该是指主程序内和主程序外的函数代码
我在想函数发布时都是“外置”的形式
那么是否需要一个外置变内置的过程
如果只是一两个函数当然手动可以完成
如果超过一定的数量级是否需要用程序来实现

另外外置函数是否也分为两种形式
一是每个函数一个脚本文件
这样就可以不用变内置直接简单的
以 call 函数名.cmd 的形式调用

二是功能相类的函数打包到一个库文件中
如果要调用就得将函数内置化了

返回值变量既要考虑可以快速存取
也要考虑可读性的问题
所以建议用类似$return的形式
另外需要考虑返回值何时被清空的问题
如果由调用方清空似乎有些麻烦
如果不清空那么又存在可能会引用前一个函数的返回值的情况
我能想到的办法
就是在函数内部setlocal的时候
同时将返回值先清空

入口参数没看出有什么约定的必要
如果需要传入且传出
那么由该函数在说明中单独约定就足够了
应该不需要作为整体的接口标准的一部分吧
天的白色影子

TOP

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

对于伪数组的构思,仅作简单示例:
  1. @echo off&setlocal enabledelayedexpansion
  2. call :setAr 1234 @#$ test
  3. echo 第2个元素 ar[1] = %ar[1]%
  4. echo;
  5. echo 最大上标 UB[ar] = %UB[ar]%
  6. echo;
  7. echo 显示“数组”中的所有元素
  8. call :listAr ar
  9. echo;
  10. pause
  11. :setAr
  12. set UB[ar]=-1
  13. for %%a in (%*) do (
  14. set /a UB[ar]+=1
  15. set "ar[!UB[ar]!]=%%a"
  16. )
  17. exit/b
  18. :listAr
  19. for /l %%a in (0 1 !UB[%1]!) do echo;!ar[%%a]!
复制代码
当然可以不定义 UB[arName],但是遍历数组时将很难兼顾通用性和效率

TOP

回复 29# CrLf


有点复杂, 调用应该简洁,可读性好

TOP

返回列表