Smalltalk 如何将代码块存储在变量中,并在需要时调用它并获取其返回值?

Smalltalk 如何将代码块存储在变量中,并在需要时调用它并获取其返回值?,smalltalk,Smalltalk,我正在用Smalltalk做一个文本冒险。它由“屏幕”组成,包括文本和其他屏幕的选择。因为我希望游戏是动态的,所以我也希望包括分支。例如,如果玩家在铁匠店里想买一把斧头,那么玩家会立即进入屏幕检查玩家是否有足够的钱,并根据这一点跳转到其他两个屏幕中的一个 我已经有了这个工作:屏幕(名为Place)有一个列表,其中第一项是函数,下面的项是参数。然而,我用一种非常丑陋的方式完成了它:第一项是一个字符串,然后在一个大的“action”方法中与之进行比较,所以它看起来像这样: 游戏数据方法: 动作方法:

我正在用Smalltalk做一个文本冒险。它由“屏幕”组成,包括文本和其他屏幕的选择。因为我希望游戏是动态的,所以我也希望包括分支。例如,如果玩家在铁匠店里想买一把斧头,那么玩家会立即进入屏幕检查玩家是否有足够的钱,并根据这一点跳转到其他两个屏幕中的一个

我已经有了这个工作:屏幕(名为
Place
)有一个列表,其中第一项是函数,下面的项是参数。然而,我用一种非常丑陋的方式完成了它:第一项是一个字符串,然后在一个大的“action”方法中与之进行比较,所以它看起来像这样:
游戏数据方法:

动作方法:(currentScreen也是一个
位置
;该类还包含一个执行实际决策的
BranchMoney
方法)

这显然不理想,我想通过这样做来压缩它:
游戏数据方法:

行动方法:

因此,游戏不需要进行字符串检查,而是直接按照我想要的方法进行

但是,它似乎不起作用-我尝试过对代码进行不同的更改,问题似乎是
currentScreen:=(currentScreen操作at:1)
行仅将currentScreen的内容替换为代码块内容–它不计算块的内容并使用其结果值(类型为
Place

我曾尝试在game data方法中使用圆括号–这会抛出一个列表越界异常,因为它试图在添加其他参数之前立即计算表达式。将游戏数据方法中的第一个项目名称更改为
currentScreen BranchMoney
似乎没有什么区别。
我还尝试在游戏数据方法中添加一个返回值,如下所示:
铁匠动作添加:[^blacksmith BranchMoney]
,这样它将有一个返回值,没有运气。在action方法中执行类似于
currentScreen:=[^currentScreen action at:1]
的操作也不起作用。

对于一些黑暗中的拍摄,我尝试了
ExternalProcedure
call
call:
方法,但也失败了。

在Smalltalk中,每个块都是一个常规对象,您可以存储和检索与任何其他对象相同的对象:

b := [self doSomething]
存储在
b
块中(就像
b:=“Hello”
b
中存储字符串一样)。我认为您缺少的是
#值
消息。要执行该块,请执行以下操作

b value   "execute self doSomething and answer with the result"
如果您的块只有一个参数,请使用
#value:

b := [:arg | self doSomethingWith: arg]
后来

b value: 17   "execute the block passing 17 as the argument"
(对于两个参数使用
#value:value:
,对于三个参数使用
#value:value:
,对于许多参数使用
#valueWithArguments:

但是请注意,这种使用块和参数数组的方法看起来并不优雅(甚至不方便)。然而,为了帮助你找到更好的选择,我们需要更多地了解你的游戏。所以,去看看
#value
(和朋友们)是否能让你进步一点,然后再回来问你的下一个问题。经过几次迭代后,我们可以引导您走向更清晰的路线


示例

b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].

在Smalltalk中,每个块都是一个常规对象,可以存储和检索与任何其他对象相同的对象:

b := [self doSomething]
存储在
b
块中(就像
b:=“Hello”
b
中存储字符串一样)。我认为您缺少的是
#值
消息。要执行该块,请执行以下操作

b value   "execute self doSomething and answer with the result"
如果您的块只有一个参数,请使用
#value:

b := [:arg | self doSomethingWith: arg]
后来

b value: 17   "execute the block passing 17 as the argument"
(对于两个参数使用
#value:value:
,对于三个参数使用
#value:value:
,对于许多参数使用
#valueWithArguments:

但是请注意,这种使用块和参数数组的方法看起来并不优雅(甚至不方便)。然而,为了帮助你找到更好的选择,我们需要更多地了解你的游戏。所以,去看看
#value
(和朋友们)是否能让你进步一点,然后再回来问你的下一个问题。经过几次迭代后,我们可以引导您走向更清晰的路线


示例

b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].

这很有效,谢谢!我想在这里输入更多内容,但是注释将所有内容压缩成一大块文本。简言之,我不再使用列表方法,而是将那些笨拙的add:s转换成类似于
铁匠动作:[铁匠分店钱:20 yes:blacksmith\u good no:blacksmith\u bad]。
,它看起来更漂亮,而且稍微不那么笨拙。再次感谢你的帮助!这很有效,谢谢!我想在这里输入更多内容,但是注释将所有内容压缩成一大块文本。简言之,我不再使用列表方法,而是将那些笨拙的add:s转换成类似于
铁匠动作:[铁匠分店钱:20 yes:blacksmith\u good no:blacksmith\u bad]。
,它看起来更漂亮,而且稍微不那么笨拙。再次感谢你的帮助!