Smalltalk 块 - 我可以显式设置返回值并停止执行该块吗?
#value: 消息发送到块时的返回值是该块中最后一句话的值。因此,[ 1 + 2. 3 + 4. ] value
的计算结果为 7。 我发现有时很难使用。有没有办法显式设置返回值并停止执行块?
作为练习,尝试在不使用我想象的 #return: 消息的情况下重写此块,看看它会变得多么难看。我一定是错过了什么。
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ].
two ifNil: [ self return: false ].
(one > two)
ifTrue: [ self return: true ]
ifFalse: [ (one < two)
ifTrue: [ self return: false ]
ifFalse: [ self return: nil ]
].
]
编辑:self return: sth
确实是无稽之谈,但在某些级别确实有意义:)
The return value of #value: message, when sent to a block, is the value of the last sentence in that block. So [ 1 + 2. 3 + 4. ] value
evaluates to 7.
I find that hard to use sometimes. Is there a way to explicitly set the returning value and stop executing the block?
For exercise, try rewriting this block without using my imaginary #return: message and see how ugly it gets. I must be missing something.
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ].
two ifNil: [ self return: false ].
(one > two)
ifTrue: [ self return: true ]
ifFalse: [ (one < two)
ifTrue: [ self return: false ]
ifFalse: [ self return: nil ]
].
]
EDIT: self return: sth
really is nonsense, but it does make sense at some level :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
没有什么比保护子句更好的了 -
blah ifTrue: [^ foo]
- 在块内,因为^
是非本地返回,而是从调用该块的方法返回比块本身。大块——就像大的东西一样——应该被重构为更小、更容易理解/易于处理的子部分,但有时这并不总是可能的。我的意思是这个答案是在您无法以通常的方式真正简化时建议尝试的选项。
如果您的块确实那么复杂,并且您无法使其变得更简单(例如,将其拆分会使信息过多地离域),那么也许您可以使用显式返回值。特别是,如果您的块不返回
nil
您可以执行类似的操作:如果您的块可以返回
nil
,您将需要另一个哨兵值:最后 - 我犹豫了建议这样做 - 你可以这样做:
返回
5
。(验证它如何与
^
和内联选择器(如#ifTrue:ifFalse:
)交互,作为读者的练习。)There's nothing like a guard clause -
blah ifTrue: [^ foo]
- inside a block, because^
is a non-local return, returning from the method calling the block rather than the block itself.Big blocks - like big anythings - should be refactored into smaller, more understandable/tractable subparts, but sometimes that's not always possible. I mean this answer to suggest options to try when you can't really simplify in the usual ways.
If your block is really that complicated, and you can't get it simpler (splitting it up delocalises the information too much, for instance) then perhaps you can use an explicit return value. In particular, if your block doesn't return
nil
you could do something likeIf your block can return
nil
, you'll need another sentinel value:Lastly - and I hesitate to suggest this - you could do this:
which returns
5
.(Verifying how this interacts with
^
and inlined selectors like#ifTrue:ifFalse:
left as an exercise for the reader.)在比较一个和两个时,您的代码似乎尝试将nil像无穷值一样处理。根据上下文,以下代码可能更具可读性:
#ifTrue:ifFalse:、#ifNil:ifNotNil: 和类似的测试方法的一个有用功能是它们返回被评估的块的值。例如,
(4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater']
计算结果为'greater'。此功能通常可以从尾部位置的嵌套块返回值。当块内的代码变得过于复杂时,我建议您将其重构为方法。但请参阅弗兰克的答案以获取解决方法。
编辑:
正如评论中所指出的,上面的代码假定为数字。我还想出了一些可以与其他类似对象一起使用的东西:
#caseOf: 构造很少使用,但它肯定比
thisContext return:
更好It seems that your code tries to handles nil like an infinity value when comparing one and two. The following code may be more readable depending on the context:
A useful feature of #ifTrue:ifFalse:, #ifNil:ifNotNil: and similar testing methods is that they return the value of the block that gets evaluated. e.g.
(4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater']
evaluates to 'greater'. This feature often makes it possible to return a value from a nested block in tail position.When the code inside a block gets too complicated I suggest your refactor it to a method. But see Frank's answer for workarounds.
Edit:
As pointed out in the comments the code above assumes numbers. I also came up with something that works with other comparable objects:
That #caseOf: construct is rarely used but it's certainly better than
thisContext return:
你想实现一些中断、继续、退出......
Smalltalk 中控制流量的常用方法是使用块。
因此,一个有趣的解决方案是使用带有 Block 返回值的辅助方法来中断流程,如所述 此处 .
现在,让我们看看如何使用它:
编辑我的第一个版本不必要地复杂,不记得是什么导致我进行了额外的间接处理:
好吧,比有用更有趣,我希望你会发现更简单和富有表现力的编码方式。
You'd like to implement some break, continue, exit...
The usual way to control flow in Smalltalk is with blocks.
So one funny solution is to use a helper method with a Block return value to break the flow, like described here .
Now, let see how to use it:
EDIT my first version was unnecessarily complex, can't remember what lead me to an additional indirection:
Well, more funny than usefull, I hope you will find more simple and expressive way to code.
正如弗兰克·希拉尔(Frank Shearar)所指出的,回报是非本地的。
由于返回是非本地的,因此必须依赖
ifTrue: block ifFalse: block
/ifFalse: block ifTrue: block
/ifNil: block ifNotNil: block
/ifNil: block ifNotNil: block
code>/ifNotNil: block ifNil: block
,并且可能在and: block
/or: block
上。当事情开始变得丑陋时(例如:缩进级别太高),请考虑将块分解为变量。请注意,外部块中的临时变量和参数不能以这种方式从内部块中引用。这就是我重新讨论这些论点的原因。
As pointed out by Frank Shearar, returns are non-local.
Since returns are non-local, one must rely on
ifTrue: block ifFalse: block
/ifFalse: block ifTrue: block
/ifNil: block ifNotNil: block
/ifNotNil: block ifNil: block
, and, possibly, onand: block
/or: block
.When things start to get ugly (e.g: too high an indentation level), consider breaking blocks into variables. Note temporary variables and arguments from outer blocks cannot be referenced from within inner blocks this way. This is why I repass the arguments.