如何将代码块存储在变量中并在需要时调用它并获取其 return 值?
How can I store a code block in a variable and call it and get its return value whenever needed?
我正在 Smalltalk 中进行一些文本冒险。它由“屏幕”组成,其中包含文本和其他屏幕的选项。因为我希望游戏是动态的,所以我也想包括分支。例如,如果玩家在铁匠铺并想买一把斧头,玩家进入的屏幕会立即检查玩家是否有足够的钱,并根据此跳转到另外两个屏幕之一。
我已经有这个工作了:屏幕(classes 命名为 Place
)有一个列表,其中第一项是函数,后面的项目是参数。然而,我以一种非常丑陋的方式完成了它:第一项是一个字符串,然后在一个大的“动作”方法中与它进行比较,所以它看起来像这样:
游戏数据方法:
blacksmith := Place new.
blacksmith choiceText: 'I would like an axe.';
blacksmith action add: 'money'; add: 20; add: blacksmith_good; add: blacksmith_bad.
action 方法:(currentScreen 也是一个 Place
;class 还包含一个 BranchMoney
方法来进行实际决策)
(currentScreen action at: 1) = 'money'
ifTrue: [
currentScreen := (currentScreen BranchMoney)
]
这显然不理想,我想通过这样做来压缩它:
游戏数据方法:
blacksmith action add: [blacksmith BranchMoney]; add: 20; add: blacksmith_good; add: blacksmith_bad.
操作方法:
currentScreen := (currentScreen action at: 1)
这样游戏就不会进行字符串检查,而是直接按照我想要的方法继续进行。
但是,它似乎不起作用 - 我尝试了对代码的不同更改,问题似乎是 currentScreen := (currentScreen action at: 1)
行只是用 [=42] 替换了 currentScreen 的内容=]代码块内容 – 它不计算块的内容并使用其类型为Place
.
的结果值
我试过在游戏数据方法中使用圆括号——这会抛出一个列表越界异常,因为它试图在添加其他参数之前立即计算表达式。将游戏数据方法中的第一个项目名称更改为 currentScreen BranchMoney
似乎没有什么不同。
我也试过在游戏数据方法中添加一个 return,像这样:blacksmith action add: [^blacksmith BranchMoney]
,这样它就会有一个 return 的值,运气不好。在 action 方法中做类似 currentScreen := [^currentScreen action at: 1]
的操作也不起作用。
对于一些在黑暗中拍摄的照片,我尝试了 ExternalProcedure
call
和 call:
方法,但也失败了。
在 Smalltalk 中,每个块都是一个常规对象,您可以像处理任何其他对象一样存储和检索它:
b := [self doSomething]
将块存储在 b
中(就像 b := 'Hello'
将字符串存储在 b
中一样)。我认为您缺少的是 #value
消息。要执行该块,请执行以下操作
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:value:
和许多 #valueWithArguments:
。)
但是请注意,这种使用块和参数数组的方法看起来不是很优雅(甚至不方便)。但是,为了帮助您找到更好的替代方案,我们需要更多地了解您的游戏。所以,去看看 #value
(和朋友)是否让你进步了一点,然后随时回到这里提出你的下一个问题。经过几次迭代后,我们可以引导您走向更清晰的路线。
例子
b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].
会产生
b value: 15 "==> 'bad'"
b value: 25 "==> 'good'"
我正在 Smalltalk 中进行一些文本冒险。它由“屏幕”组成,其中包含文本和其他屏幕的选项。因为我希望游戏是动态的,所以我也想包括分支。例如,如果玩家在铁匠铺并想买一把斧头,玩家进入的屏幕会立即检查玩家是否有足够的钱,并根据此跳转到另外两个屏幕之一。
我已经有这个工作了:屏幕(classes 命名为 Place
)有一个列表,其中第一项是函数,后面的项目是参数。然而,我以一种非常丑陋的方式完成了它:第一项是一个字符串,然后在一个大的“动作”方法中与它进行比较,所以它看起来像这样:
游戏数据方法:
blacksmith := Place new.
blacksmith choiceText: 'I would like an axe.';
blacksmith action add: 'money'; add: 20; add: blacksmith_good; add: blacksmith_bad.
action 方法:(currentScreen 也是一个 Place
;class 还包含一个 BranchMoney
方法来进行实际决策)
(currentScreen action at: 1) = 'money'
ifTrue: [
currentScreen := (currentScreen BranchMoney)
]
这显然不理想,我想通过这样做来压缩它:
游戏数据方法:
blacksmith action add: [blacksmith BranchMoney]; add: 20; add: blacksmith_good; add: blacksmith_bad.
操作方法:
currentScreen := (currentScreen action at: 1)
这样游戏就不会进行字符串检查,而是直接按照我想要的方法继续进行。
但是,它似乎不起作用 - 我尝试了对代码的不同更改,问题似乎是 currentScreen := (currentScreen action at: 1)
行只是用 [=42] 替换了 currentScreen 的内容=]代码块内容 – 它不计算块的内容并使用其类型为Place
.
我试过在游戏数据方法中使用圆括号——这会抛出一个列表越界异常,因为它试图在添加其他参数之前立即计算表达式。将游戏数据方法中的第一个项目名称更改为 currentScreen BranchMoney
似乎没有什么不同。
我也试过在游戏数据方法中添加一个 return,像这样:blacksmith action add: [^blacksmith BranchMoney]
,这样它就会有一个 return 的值,运气不好。在 action 方法中做类似 currentScreen := [^currentScreen action at: 1]
的操作也不起作用。
对于一些在黑暗中拍摄的照片,我尝试了 ExternalProcedure
call
和 call:
方法,但也失败了。
在 Smalltalk 中,每个块都是一个常规对象,您可以像处理任何其他对象一样存储和检索它:
b := [self doSomething]
将块存储在 b
中(就像 b := 'Hello'
将字符串存储在 b
中一样)。我认为您缺少的是 #value
消息。要执行该块,请执行以下操作
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:value:
和许多 #valueWithArguments:
。)
但是请注意,这种使用块和参数数组的方法看起来不是很优雅(甚至不方便)。但是,为了帮助您找到更好的替代方案,我们需要更多地了解您的游戏。所以,去看看 #value
(和朋友)是否让你进步了一点,然后随时回到这里提出你的下一个问题。经过几次迭代后,我们可以引导您走向更清晰的路线。
例子
b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].
会产生
b value: 15 "==> 'bad'"
b value: 25 "==> 'good'"