免责声明:我写了function
。
其余的答案已经很好地涵盖了标准行为,所以让我们跳过它。
让我们看看您对method
函数的建议,以便更轻松地编写引用对象单词的对象绑定函数。通过一些调整,它可能是对 Rebol 的有用补充。
问题
以正常、正确的方式做事并不总是奏效。从 jvargas 获取一些代码:
o: make object! [
x: 1
y: 1
z: function [][
z: x + y
]
m: function [][
self/x: 2
self/y: 2
z: x * y
]
]
假设您需要保护单词x
并防止y
从对象外部访问 - 这是人们首先编写方法的主要原因之一。Rebol 提供了一个protect/hide
功能。所以让我们使用它:
protect/hide/words in o [x y]
一旦你隐藏了这些词,它们就不能被访问,除非通过在它们受到保护之前绑定到它们的词——我们仍然希望现有的绑定能够工作,这样我们就可以编写允许访问这些词的特权代码,但想要阻止外部代码。因此,任何尝试访问这些单词的新代码或“外部”代码都会失败。o/x
在这种情况下,外部代码意味着通过路径表达式(如)或通过绑定表达式(如 )引用单词in o 'x
。
不幸的是,对于上面的代码,这意味着self/x
andself/y
表达式也不起作用。如果他们这样做了,那么绕过这样的限制就太容易了:
do in o [self/x: "something horrible"]
这就是我们制作 的原因之一function/with
,所以它可以像 Ladislav 建议的那样使用。但function/with
也不一定能工作,因为它也意味着能够从外部工作 - 它显式地将函数体绑定到提供的对象,这增加了它在高级代码中的功能,但如果这些话在这里对我们没有帮助在构造方法之前被隐藏:
bar: object [
x: 10
y: 20
protect/hide/words [x y]
foo: function/with [] [
x: 304
y: 304
c: 12-Dec-2012
d: $0.50
] self
]
调用function/with
不会保留x
and y
,因为它看不到它们(它们已经隐藏),所以这些词对于结果函数来说是本地的。要执行您想要的操作,您必须使用另一个选项:
bar: object [
x: 10
y: 20
protect/hide/words [x y]
foo: function/extern [] [
x: 304
y: 304
c: 12-Dec-2012
d: $0.50
] [x y]
]
这只是function
跳过添加x
和y
到本地,并且由于它们之前与对象的其余代码块绑定到对象,因此在隐藏单词之前,它们仍然会被绑定并且仍然有效。
这太棘手了。我们可以从一个简单的替代方案中受益。
一个办法
这是您的函数的清理版本,method
可以解决一些问题:
method: func [
"Defines an object function, all set-words local except object words."
:name [set-word!] "The name of the function (modified)"
spec [block!] "Help string (opt) followed by arg words (and opt type and string)"
body [block!] "The body block of the method"
] [
unless find spec: copy/deep spec /local [append spec [
/local
]]
body: copy/deep body
append spec collect-words/deep/set/ignore body
append append copy spec 'self words-of bind? name
set name make function! reduce [spec body]
]
你像这样使用它:
bar: object [
x: 10
y: 20
method foo: [] [
x: 304
y: 304
c: 12-Dec-2012
d: $0.50
]
]
您可能会注意到,这看起来比function/with
or your更尴尬method
,几乎就像它的语法一样。您可能还注意到您不必通过self
或单词列表 - 那么它是如何工作的,因为 Rebol 没有范围?
诀窍在于,此函数使您将方法名称的 set-word 放在 word之后,method
而不是之前。这就是使它看起来像其他编程语言中的方法语法的原因。然而,对我们来说,它把方法名变成了method
函数的参数,有了这个参数,我们就可以通过单词的绑定得到原始对象,然后从中得到单词列表。
还有一些其他因素可以使这种绑定技巧起作用。通过命名此函数method
并在文档字符串中提及对象,我们几乎可以确保此函数通常仅用于对象或模块中。对象和模块从它们的代码块中的集合词中收集它们的词。通过确保名称必须是一个集合词,这使得它可能被绑定到对象或模块。我们声明它:name
以阻止将 set-word 视为赋值表达式,然后在函数中显式设置它,就像人们可能天真的期望的那样。
作为 , 的一个优势function/with
,method
它不会将函数体重新绑定到对象,它只是跳过对象的单词 likefunction/extern
并留下现有的绑定。专业化让它变得更简单,并且有更少的开销作为奖励。
新的method
也比原来的有几个优点method
:
- 该循环中的额外代码具有在函数
foreach
中保留单词的副作用,以及取消设置单个细化组的本地单词的效果,而这些单词通常是默认的。函数本地词故意默认为 none,这会使它们的行为不一致。这是不必要的,也是不明智的。unset
none
- 这个
self
词很特殊,words-of
如果你尝试分配它,它不会被返回并显式触发错误,以帮助你避免错误。您的代码丢失了该错误,其中的代码function
旨在保留它。考虑到意外覆盖是多么糟糕的想法self
,最好要求人们通过在函数 locals 中声明来明确覆盖它。
exclude
不适用于具有嵌套块的块,因此您的代码不适用于声明了类型的函数规范。这就是为什么首先function
使用这些append
调用。
这是否符合您的目的?