范围如何在Io中起作用?

时间:2013-11-12 03:04:51

标签: scope closures iolanguage

我不太确定变量范围在 Io 中的作用。文档说它有闭包,但我似乎无法在idxnext方法中看到prev。父可见性是关闭的关键前提,那么它们如何工作?

List iterator := method(
    idx := 0

    itr := Object clone
    itr next := method(
        idx = idx + 1
        return self at(idx)
    )

    itr prev := method(
        idx = idx - 1
        return self at(idx)
    ) 

    return itr
)

应该如何实现?

1 个答案:

答案 0 :(得分:7)

所以你从根本上误解了方法和块的工作方式,但没关系。让我们回顾一下基础知识:

  1. 方法是在按名称调用时激活的块,其范围设置为nil。当我们谈论范围时。
  2. 块的范围设置为创建它们的上下文。
  3. context表示本地对象,基本上是堆栈帧。范围意味着在调用块/方法时谁将成为块激活的“发送者”。您可以通过方法或块上下文中的call sender对象来访问它。

    现在,让我们来看看你的代码。它几乎是完美的,只有一件事缺失,而且不明显。

    由于方法具有动态范围,因此它们的scope消息返回nil。这表示评估者应该将接收到该消息的任何对象作为发送上下文传递。我们不希望这种行为,我们希望捕获一些范围,特别是我们定义的iter方法的本地化。让我们看一个更正的例子:

    List iterator := method(
        idx := 0
    
        itr := Object clone
        itr next := method(
            idx = idx + 1
            at(idx)
        ) setScope(thisContext)
    
        itr prev := method(
            idx = idx - 1
            at(idx)
        ) setScope(thisContext)
    
        itr
    )
    

    我简化了机构,但它们在功能方面没有改变(除少数消息发送外)。重要的是在分配给setScope / next之前传递给方法的prev调用。我本可以选择将其重写为:

    iter prev := block(
        idx = idx - 1
        at(idx)
    ) setIsActivatable(true)
    

    但是我必须让块可激活,因为默认情况下块不可激活。上面的代码和使用itr prev的更正method()在功能上是等效的。

    方法不是闭包,块是。块只是一个范围非零的方法,它们是同一个对象。