Rebol中用于函数和闭包的低级原语是FUNC和CLOS。如果没有明确告诉FUNC或CLOS创建本地的东西,那么分配将不是本地的。
x: 10
y: 20
foo: func [/local x] [
x: 304
y: 304
]
foo
print [{x is} x {and} {y is} y]
这将输出:
x为10,y为304
更高级别的例程FUNCTION和CLOSURE在默认库中写为Rebol代码。他们在身体上扫描SET-WORD类别的符号(例如x:
和y:
)。然后他们自动生成一个增强函数规范,将它们添加为/ LOCAL:
x: 10
y: 20
foo: function [] [
x: 304
y: 304
]
foo
print [{x is} x {and} {y is} y]
这将输出:
x为10,y为20
几乎所有的时间都好,所以这些得到更漂亮的名字是件好事。但是,如何将FUNCTION用作对象成员呢?
bar: object [
x: 10
y: 20
foo: function [] [
x: 304
y: 304
c: 12-Dec-2012
d: $0.50
]
]
这不会像在对象中的其他语言中那样,假设默认情况下成员不会被局部变量隐藏。如果他们希望foo
在对象中设置的任何单词上扮演类似FUNC的角色,那么该怎么办?
我唯一想到的是将self
传递给FUNCTION代码的变体,例如:
method: func [
me [object!] {always the parameter "self"?}
spec [block!]
body [block!]
] [
unless find spec: copy/deep spec /local [append spec [
/local
]]
body: copy/deep body
append spec exclude collect-words/deep/set/ignore body words-of me spec
foreach l next find spec /local [
if refinement? l [
break
]
insert body to-lit-word l
insert body 'unset
]
make function! reduce [spec body]
]
但是你必须写 foo:method self [] [...] 这是罗嗦(假设这种方法甚至是合法的)。
有没有任何技巧可以通过self
,或其他一些成语来支持这种愿望?或者每个人都只使用FUNC作为对象成员?
答案 0 :(得分:4)
描述的行为来自rebol中使用的动态范围。 :method
的建议定义从函数的body
推断出本地化,同时允许访问对象的实例变量,而无需程序员的任何声明工作。在存在动态范围的情况下,这种类型的泄漏抽象是危险的。例如:
程序员写下这个初始版本:
o: make object! [
x: 1
y: 1
m: method [][
x: 2
y: 2
z: x * y
]
]
稍后进行了许多修订,另一位程序员决定将代码修改为:
o: make object! [
x: 1
y: 1
z: method [][
z: x + y
]
m: method [][
x: 2
y: 2
z: x * y
]
]
根据执行路径,修改后的代码可能会产生不同的结果。调用o/m
方法将覆盖o/z
方法。因此,所提出的实施引入了一个惊喜的元素。
通过保存程序员清楚地表达其意图的努力,代码变得脆弱。当你的意思是这样的时候,你可以明确地想要使用self
来成为对象的成员:
o: make object! [
x: 1
y: 1
z: function [][
z: x + y
]
m: function [][
self/x: 2
self/y: 2
z: x * y
]
]
然后,您可以使用FUNCTION和CLOSURE,它是可读且明确的。
答案 1 :(得分:2)
目前这种方法有效,但可能并不完全符合您的要求:
bar: object [
x: 10
y: 20
foo: function/with [] [
x: 304
y: 304
c: 12-Dec-2012
d: $0.50
] self
]
答案 2 :(得分:2)
免责声明:我写了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
和self/y
表达式也不会起作用。如果他们这样做,那么绕过这样的限制就太容易了:
do in o [self/x: "something horrible"]
这是我们制作function/with
的原因之一,因此它可以像Ladislav建议的那样使用。但是function/with
不一定能够工作,因为它也意味着能够从外部工作 - 它明确地将函数体绑定到提供的对象,这增加了它在高级代码中的能力,但不是&# 39;如果在构造方法之前隐藏了单词,请帮助我们:
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
和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
或你的method
更难以尴尬,几乎就像它的语法一样。您可能还注意到,您不必通过self
或单词列表 - 所以考虑到Rebol缺少范围,它是如何工作的?
诀窍是这个函数可以让你在单词 还有一些因素会使这种绑定技巧发挥作用。通过命名此函数 作为优于 新 这是否符合您的目的?method
后面放置方法名的set-word,而不是它。这就是它看起来像其他编程语言中的方法语法。但是,对于我们来说,它将方法名称转换为method
函数的参数,使用该参数,我们可以通过绑定单词来获取原始对象,然后从中获取单词列表。 / p>
method
并提及doc字符串中的对象,我们几乎确保此函数通常仅用于对象或模块中。对象和模块从其代码块中的set-words收集它们的单词。通过确保名称必须是一个set-word,这可能会绑定到对象或模块。我们用:name
声明它来阻止被视为赋值表达式的set-word,然后在函数中显式地将它设置为某人可能天真地期望它的方式。function/with
的优势,method
不会将函数体重新绑定到对象,它只会跳过对象的function/extern
之类的字词并离开现有的绑定。专业化让它变得更简单,并且作为奖励有更少的开销。method
与原始method
相比还有一些优势:
foreach
循环中的额外代码有副作用
在函数中保留单词unset
,以及效果
在何时取消单个细化组的本地单词
通常这些单词默认为none
。功能本地词
默认情况下没有任何意图,这将使他们的行为
不一致。这是不必要的,也是不明智的。self
字是特殊的,words-of
并未返回
如果您尝试分配错误,则显式触发错误,以帮助您
避免错误。您的代码丢失了该错误,function
中的代码
旨在保护它。考虑到它的想法有多糟糕
意外覆盖self
,最好要求人们
通过在函数locals中声明它来显式覆盖它。exclude
不能处理嵌套块的块,所以你的
代码不会使用声明类型的函数规范。
这就是function
首先使用append
次调用的原因。