【问题标题】:How does scope work in Io?范围在 Io 中是如何工作的?
【发布时间】:2013-11-24 01:37:05
【问题描述】:

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

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
)

这应该如何实现?

【问题讨论】:

    标签: scope closures iolanguage


    【解决方案1】:

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

    1. 方法是在您按名称调用它们时激活的块,其范围设置为 nil。当我们谈论范围时。
    2. 块的范围设置为创建它们的上下文。

    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
    )
    

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

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

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

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

    【讨论】:

    • 太棒了。如果我能给你更多的代表这个答案,我会的。我真的很喜欢 Io,但是发现文档非常不显眼,关于块和方法的部分非常简约。你能指出我更全面的参考吗?再次感谢!
    • 大多数人只是在 #io 频道中通过 irc.freenode.net 跳,然后等我转储我的大脑。 :) 不,在这方面我恐怕没有其他建议给你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2015-04-24
    • 2019-01-17
    • 1970-01-01
    相关资源
    最近更新 更多