假设我有一个班级:
(class object%
(init val)
(define/public (get-val) ... )
(define/public (get-norm) ... ))
为什么我有两个实例foo
和bar
我可以这样做:
(eval '(send foo get-val))
但不能这样做:
(for/list ([who '(foo bar)])
(for/list ([what '(get-val get-norm)])
(eval (cons 'send (list who what)))))
在后一种情况下,我收到错误:
send: unbound identifier;
also, no #%app syntax transformer is bound in: send
获得我想要的结果的好方法是什么?
UPDATE:我发现嵌套循环在交互模式下工作正常,但如果在定义区域中写入则会产生错误。任何人都可以解释一下这个诀窍吗?
答案 0 :(得分:2)
您可以使用:
(for*/list ([who (list foo bar)]
[what '(get-val get-norm)])
(dynamic-send who what))
原因是'(foo bar)
是包含两个符号的列表foo
和bar
,而不是包含变量值的列表foo
和bar
;你必须使用(list foo bar)
。
此外,为了能够send
变量中的方法名称,而不是直接命名方法,您必须使用dynamic-send
。
请注意,我的代码不使用eval
,您也不应该使用eval
。大多数情况下,您永远不需要使用{{1}},并且尽可能避免使用它。
答案 1 :(得分:2)
问题在于使用eval
。在REPL中使用eval
工作正常,因为REPL为eval
提供了racket
的所有导出的命名空间。 REPL本质上是先运行模块,然后创建一个包含所有结果定义的新命名空间,并在使用该命名空间输入的任何内容上调用eval
,因此在调用send
时定义了eval
。但是,在定义窗口中,您需要自己为eval
提供命名空间,以使其正常工作,因为初始当前命名空间为空。所以你可以做的是将它添加到定义的开头:
(define ns (make-base-namespace))
现在,无论何时使用eval
,都将ns
作为命名空间参数传递,如(eval '(+ 1 2)
ns中所示。但是有很多警告。
(define foo 3)
,(eval '(+ 1 foo) ns)
无法工作 - foo
未在ns
命名空间中定义,则会在当前模块中定义命名空间。racket/base
。你必须做一些eval-shenanigans或一些命名空间 - 恶作剧来要求racket/class
。(current-namespace)
参数的值,但这附带了它自己特别注意的警告和复杂性。核心问题是eval
非常非常非常适合工作,更不用说最好的工具了。在你不知道发生了什么的情况下,有许多角落的情况和陷阱可能会蔓延到你身上,更不用说可能会恶化的性能问题了。除非你真的知道自己在做什么,并确信那里没有更好的选择,否则就像瘟疫一样避免它。
请问您为什么需要在问题中使用foo
处理bar
和eval
?
有关eval
的更多信息,请参阅the Racket documentation,这是非常彻底且有用的资源。