Lisp程序结构
个人经验,主要写给自己;;在明经混了许多年,又在晓东混了几年了,渐发现原来写的程序不是太合理,全改又没有那么多精力了.
;;对于lisp程序结构,我自己有了自己的看法,自己总结一下,今后套用这种格式。 自贡黄明儒 2014.10.15
;;1 建立通用和自定义函数库,分别保存为Public.lsp和MyLsp.lsp,今后加载和修改就方便了
;;今后只需要加载两个文件,这就方便了;通用函数的建立,给自己修改来方便。
;;2 自定函数
(defun C:w1 (/ CMD1 OSM1 SS)
;;2.1 错误处理
;;定义在函数内部,作用范围也只限于此函数。
;;写在开头,以保证后面的代码发生错误,均会执行错误处理。
(defun *error* (msg)
;;2.1.1 写在开头,错误处理反跟踪,找出调试错误所在。调试完毕后,可注释掉
(vl-bt)
;;2.1.2 如果命令还在执行,中断它
(while (not (equal (getvar "cmdnames") "")) (command nil))
;;2.1.3 在错误发生之前改变的变量,发生错误时后面的代码不再执行,必须恢复
(setvar "nomutt" 0);容量忘了它,没恢复成0后面使用起来怪怪的
(cond (cmd1 (setvar 'cmdecho cmd1)))
(cond (osm1 (setvar 'osmode osm1)))
(princ "\n 出错啦!")
;;2.1.4 静默退出
(princ)
)
;;2.2 其它临时函数,非通用的
()
;;2.3 一般说来,执行一个程序,总是要选择对象。如果希望先择后执行,就要有这句,而且写在开头
(cond ((cadr (ssgetfirst)) (setq ss (ssget "_P" '((0 . "*TEXT"))))))
;;2.4 检查加载vl扩展,有这句没有坏处,也不会造成程序多大的额外负担,因为如果已经加载扩展,不做任何事情
(VL-LOAD-COM)
;;2.5 *acad* *DOC*是常用的,不必释放。前面加*号,编辑器检查形参时会把它们排在前面,便于我们去除
(or *acad* (setq *acad* (vlax-get-acad-object)))
(or *DOC* (setq *DOC* (vla-get-ActiveDocument *acad*)))
;;2.6 获取并修改变量
(setq cmd1 (getvar "cmdecho"));如果后面用到command,不希望显示一些信息
(setvar "cmdecho" 0)
(setq osm1 (getvar "osmode"));如果后面用到command画图,不关闭捕捉,就可能不是我们需要的点
(setvar "osmode" 0)
;;2.7 编组开始
;;便于按后悔键Ctrl+Z时,一步退到位 我以前没读过书,现在来上成人扫盲班还来得及 *acad*不释放还可以 *DOC*总是用一个的话,多文档环境下,文档一切换就有问题了。
补充一点个人经验,我们做代码,可维护性要放在更高的位置。变量、函数的命名情愿长一点,要体现其含义,多注释; 多写短小的代码; 每个函数功能尽可能单一,提高函数的利用率;
比如代码超过二、三十行,局部变量超过五、六个的函数,就看下有没有可能拆分成几个函数,对于维护和提高代码的质量都大有好处 很好,实用,谢谢 vectra 发表于 2014-10-15 16:19 static/image/common/back.gif
*acad*不释放还可以 *DOC*总是用一个的话,多文档环境下,文档一切换就有问题了。
补充一点个人经验,我 ...
现在是不是妥了
提点改进意见:
1、如果每个自定函数都要定义这么复杂,而且相似程度又高的*error*函数,那么,提取出该函数公共的、相似的部分,做成一个通用函数,比如public-error-handler;自定义函数中的*error*只是简单地引用public-error-handler。一切为了“减少允余”原则。
2、 建议*error*放在局部变量表中去,貌似可以不影响全局错误函数,可以完全不干涉CAD的错误处理机制。(未深入测试,参LEE-MAC代码)
3、 (cond (*doc* (vlax-release-object *doc*)))
没有必要,*doc*还是建议做成局部变量,退出就释放了;document是CAD自己维护的,也不可能释放掉。vlax-release-object只在用户启动的外部对象时需要,如excel什么的。
4、(gc)可以取消,lisp文档较缺,机制不明确。但根据.net的资料,频繁强制回收内存会造成性能问题。还是多检查局部变量,意外的全局变量即使GC也不能回收。
5、 (defun c:w1 ()..)的做法并不太好,考虑别人也有个命令,也定义成了W1,甚至都VLX封闭了。可以定义为MyCustomFunctionA,然后再通过别名或者重定义命令调用。当然简单的应用也不用考虑这么多啦
6、没有sel-method参数的ssget本身支持先命令或先选择的方式,试下(ssget '((0 . "*TEXT")))
7、变量设置可参考gxl-error-init函数 http://bbs.mjtd.com/forum.php?mod=viewthread&tid=100616 本帖最后由 自贡黄明儒 于 2014-10-16 10:54 编辑
vectra 发表于 2014-10-16 10:24 static/image/common/back.gif
提点改进意见:
1、如果每个自定函数都要定义这么复杂,而且相似程度又高的*error*函数,那么,提取出该函 ...
第2条,内外都可以放一个*error*函数,都会执行的。
最后一条,是G版的,整得很复杂,看得人头晕 学习了,现在还没有这么复杂的程序,不过也许正是没有做到上面这些,使得自己做不了复杂程序 请继续,洗耳恭听 用下面的代码简单测试了下
(defun *error* (s)
(princ "1")
)
(defun test (/ *error*)
(defun *error* (s)
(princ "2")
)
(/ 1 0)
)
; 2 表格 从 #<editor "<未命名-0> 正在加载..."> 加载
_$ *error*
#<USUBR @0c5a74ec *ERROR*>
_$ (test)
2
_$ *error*
#<USUBR @0c5a74ec *ERROR*>
_$ (test)
2
_$ (/ 1 0)
1
可见,test内的错误由test内部定义的*error*处理,而在test函数外部的错误由外面定义的*error处理。没有看到同时调用内外部*error*的情况
页:
[1]
2