明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 5600|回复: 38

[讨论] Lee Mac大神为什么这样写vla容器的函数?

[复制链接]
发表于 2019-7-31 16:44:17 | 显示全部楼层 |阅读模式
Lee Mac大神在写获取vla容器的时候,一般写成这种格式:
  1. (defun LM:acdoc nil
  2.   (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
  3.   (LM:acdoc)
  4. )

而不是传统的
  1. (defun LM:acdoc nil
  2.         (vla-get-activedocument (vlax-get-acad-object))
  3. )

这样写有什么好处吗?是不是为了同一个doc在多次调用的时候,避免重复求值?
发表于 2019-8-1 00:02:17 | 显示全部楼层
本帖最后由 highflybird 于 2019-8-1 00:13 编辑

首先我的个人观点觉得这个地方完全是Lee秀技巧有点过了,但实际并未达到他的目的。
1、分析他的这段代码:
  1. (defun LM:acdoc        nil
  2.   (eval    (list 'defun              'LM:acdoc
  3.               'nil
  4.               (vla-get-activedocument (vlax-get-acad-object))
  5.         )
  6.   )
  7.   (LM:acdoc)
  8. )


第一段 :   
  1.   (eval        (list 'defun
  2.               'LM:acdoc
  3.               'nil
  4.               (vla-get-activedocument (vlax-get-acad-object))
  5.         )
  6.   )


从结果来说,完全等同于
  1.   
  2. (eval        '(defun LM:acdoc () (vla-get-activedocument (vlax-get-acad-object))))

也就是下面的语句:
  1.    (defun LM:acdoc nil
  2.     (vla-get-activedocument (vlax-get-acad-object))
  3.   )

也就是说 eval,eval的是对一个函数进行定义,仅仅是定义,但并未对这个函数求值。
2、但从效率来说,Lee的反而低了点,因为用了eval
所以 ,Lee的这段代码就等于下面的:

  1. (defun LM:acdoc        nil
  2.   (defun LM:acdoc nil
  3.     (vla-get-activedocument (vlax-get-acad-object))
  4.   )
  5.   (LM:acdoc)
  6. )


3、这这个函数粗一看,是递归的,递归没做处理,就会变成死循环,但是为何没有呢?
是因为 Lee 定义了这个名为 LM:acdoc的函数,结果在函数内部又重新定义了一下这个函数
所以函数返回的时候,用的却是函数里面的定义。
以一个简单的例子来说

  1. (defun A ()
  2.   (defun A ()
  3.     (+ 1 1)
  4.   )
  5.   (A)
  6. )



我开始定义了一个名为A 的函数,在函数里面又调用了A ,如果在函数内没有重新定义A函数,这个函数将陷入死循环,很快LISP就会有错误提示:
vlide 出现硬错误 ***
已达内部堆栈限制 (模拟)

说明是递归函数没设置终止条件。但正是因为在函数里面重新定义了函数体,所以才避免的这样情况,最后执行的是在函数内的定义。

4、Lee 的本义是只是将下面的语句执行一次求值:
(vla-get-activedocument (vlax-get-acad-object))
但是达到效果了吗?没,
用户可以自行用断点运行,发现结果还是要进行求值,所以Lee的想法落空了。

因此,就这个函数来说,我个人观点认识是Lee的做法有点过了。





点评

看完后面的回复,这个猜测可以删除了,不好意思,怎么删除这个  发表于 2020-4-16 15:42
个人拙见,是不是有指针值刷新的问题,重新求值这样获得的值就刷新了,是不是直接定义有过程堆栈?或者就像Microsoft.XMLHTTP异步返回?或者调用完了它会自动清除多余的指针指向?或者它会开放一个新的线程?猜测  发表于 2020-4-16 15:21
函数里面,不是先调用后求值而是先求值后调用。所以返回值是调用后的结果,不是求值的结果。  发表于 2019-8-1 16:17
我收回此楼的说法。 eval list 和 eval '的效果不同。  发表于 2019-8-1 12:24
发表于 2019-8-1 12:45:29 | 显示全部楼层
nzl1116 发表于 2019-8-1 12:28
我被你搞偏了,你那个(alert "a")就是 nil
不管怎么说,就是用函数储存,函数要执行defun表达式,而用变 ...

我说的肯定是对的
(eval (list 'defun 'LM:acdoc '() (alert "a") (vla-get-activedocument (vlax-get-acad-object))));先计算(alert "a"),返回nil

(eval (list 'defun 'LM:acdoc nil nil (vla-get-activedocument (vlax-get-acad-object))))
;再计算vlax-get-acad-object,返回对象

(eval (list 'defun 'LM:acdoc nil nil (vla-get-activedocument #<VLA-OBJECT IAcadApplication 00007ff71ec6c910>)))
;再计算vla-get-activedocument,返回对象

(eval (list 'defun 'LM:acdoc nil nil #<VLA-OBJECT IAcadDocument 0000000030636888>)
;然后list得到一个表(DEFUN LM:ACDOC nil nil #<VLA-OBJECT IAcadDocument 0000000030636888>),这个表里的都是值,不再是代码
再然后就是重新定义函数,这个函数里的只有值,你再调用函数时肯定不会再计算了,直接就返回值了.

他就是把值存在了函数里

就相当于
(defun LM:ACDOC ()
"a"
1
nil
2
)
这个函数里只有值 ,不可能有其它东西
你再调用的时候,他只返回最后的1个值,不管你这个函数前面有什么值
 楼主| 发表于 2019-8-1 10:22:36 | 显示全部楼层
本帖最后由 mayingjun 于 2019-8-1 10:30 编辑
highflybird 发表于 2019-8-1 00:02
首先我的个人观点觉得这个地方完全是Lee秀技巧有点过了,但实际并未达到他的目的。
1、分析他的这段代码: ...

我把程序的格式调整成这样。
  1. (defun LM:acdoc nil
  2.   (eval
  3.       (list 'defun 'LM:acdoc 'nil
  4.         (alert "aaaa")
  5.         (vla-get-activedocument (vlax-get-acad-object))
  6.       )
  7.   )
  8.   (LM:acdoc)
  9. )

并在 (vla-get-activedocument (vlax-get-acad-object)) 的最后)处设置了断点,发现第一次运行时,alert和断点被触发,返回值是:#<VLA-OBJECT IAcadDocument 0e9db808>。再次执行时,两个都没有触发,直接得到了#<VLA-OBJECT IAcadDocument 0e9db808>。看来这种写法还是有作用的。
而写成你说的那种方式
  1. (defun LM:acdoc nil
  2.   (defun LM:acdoc nil
  3.     (alert "aaaa")
  4.     (vla-get-activedocument (vlax-get-acad-object))
  5.   )
  6.   (LM:acdoc)
  7. )

则再次运行的时候,alert和断点都会被触发。



发表于 2019-7-31 18:53:44 来自手机 | 显示全部楼层
可能只是为了新鲜
发表于 2019-8-1 07:35:07 | 显示全部楼层
天高任鸟飞,确实厉害
发表于 2019-8-1 07:49:58 | 显示全部楼层
本帖最后由 琴剑江山_10184 于 2020-2-22 19:34 编辑
highflybird 发表于 2019-8-1 00:02
首先我的个人观点觉得这个地方完全是Lee秀技巧有点过了,但实际并未达到他的目的。
1、分析他的这段代码: ...

;;;;;;


 楼主| 发表于 2019-8-1 08:52:18 | 显示全部楼层
highflybird 发表于 2019-8-1 00:02
首先我的个人观点觉得这个地方完全是Lee秀技巧有点过了,但实际并未达到他的目的。
1、分析他的这段代码: ...

那要想达到一次求值的目的,是否只能用全局变量了?
发表于 2019-8-1 10:24:25 | 显示全部楼层
本帖最后由 highflybir 于 2019-8-1 10:31 编辑
mayingjun 发表于 2019-8-1 08:52
那要想达到一次求值的目的,是否只能用全局变量了?

就这种情况来说,应该是要用全局变量。其实,用函数也没关系,这个地方求值对于vlisp内部来说,求过一次值后,就不会再去eval,因为vlisp给你返回的是一个引用,类似于指针。 vla-get 与 vlax-create是不同的。因为这两个都是用get方式创建的。
所以,不管你用 多少次(vlax-get-acad-object) 和(vla-get-ActiveDocument (vlax-get-acad-object)),得到的结果是相同的.
就像下面的样子:
#<VLA-OBJECT IAcadApplication 00007ff6634dc910>
#<VLA-OBJECT IAcadDocument 0000000037039cc8>
而用vlax-create-object  得到的是不同的引用。
 楼主| 发表于 2019-8-1 10:31:42 | 显示全部楼层
highflybir 发表于 2019-8-1 10:24
就这种情况来说,应该是要用全局变量。其实,用函数也没关系,这个地方求值对于vlisp内部来说,求过一次 ...

看我上面的测试,lee mac这种写法还是有效的。
发表于 2019-8-1 10:35:59 | 显示全部楼层
本帖最后由 highflybir 于 2019-8-1 10:42 编辑
mayingjun 发表于 2019-8-1 10:31
看我上面的测试,lee mac这种写法还是有效的。

嗯,看来lee是对的,我再仔细看看eval那段.看来,(  (eval
    '(defun
          LM:acdoc
          nil
          (alert "bbb")
          (vla-get-activedocument (vlax-get-acad-object))
    )
  )

  (eval
    (list 'defun
          'LM:acdoc
          'nil
          (alert "bbb")
          (vla-get-activedocument (vlax-get-acad-object))
    )
  )并不相等。

点评

'(1 (prompt "1"))这里的prompt不会执行;(list '1 (prompt "1"))这里的prompt会执行。所以和eval函数没有关系。个人觉得,Lee Mac的函数主要是要利用eval只求值一次,直接获取上次执行的结果。  发表于 2019-8-1 16:40
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-5-18 15:20 , Processed in 0.198998 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表