您可以将 "next" 传回调用当前函数的函数吗?
Can you pass a "next" back to the function that called the current function?
我有一系列嵌套的 each
循环遍历卡片列表。这些循环调用其他子函数,测试是否满足某些条件以便继续。
def card_handler
cards.each do |card|
#some non-relevant code is here on my end
already_sent?
end
end
def already_sent?
# allows for checking if different emails have been sent on the same card
if list_action == 147
a_s_helper(p1_label)
elsif list_action == 146
a_s_helper(p2_label)
elsif list_action == 145
a_s_helper(p3_label)
end
end
def a_s_helper(label)
if card::card_labels.include? label
# if the card already has the label, I want to log the error and return all the way to the next card in the iteration
puts '\n Order info: \n id: #{id} \n Email already sent'
next
# doesn't work
else
real_id?
end
end
就像我在 a_s_helper 的评论中所说的那样,如果卡片已经有标签,我想记录错误并 return 一直到迭代中的下一张卡片。我从当前设置中收到“下一个无效”错误。
有没有办法 return 一个 next
回到父函数或循环?
next
仅在循环的直接上下文中有效。一旦你调用了一个方法,你就不再直接处于那个循环上下文中。您不能像这样使用 next 来短路外环。
您有两个选择:
- Return 来自谓词函数的状态(这是你应该做的,来自谓词!)并基于这些使循环短路,或者
- 使用 Ruby 的
catch...throw
构造(这不是它的 raise/rescue 异常处理程序,而是 something like a block-scoped GOTO statement)
选项 1:Return查看状态。这是最合适的方法,IMO。谓词方法(那些以 ? 结尾的方法)通常应该 return 布尔值并且是幂等的(也就是说,应该没有副作用,例如记录语句)。它们通常用于提出 yes/no 问题。根据这个问题决定做什么最好不在他们的范围之内。
def card_handler
cards.each do |card|
#some non-relevant code is here on my end
if already_sent?
puts '\n Order info: \n id: #{id} \n Email already sent'
next
end
end
end
def already_sent?
case list_action
when 145
a_s_helper(p3_label)
when 145
a_s_helper(p2_label)
when 147
a_s_helper(p1_label)
end
end
def a_s_helper(label)
card::card_labels.include? label
end
这会导致您的助手 return 循环的真值或假值,它可以决定记录消息并转到下一次迭代。
选项 2:catch...throw
def card_handler
cards.each do |card|
# Put all your code that should nomally run inside the catch block. If
# the message :email_sent is thrown, then Ruby will zip up the stack and
# resume execution at the end of the block. This will skip any unexecuted
# code in the block, essentially terminating the execution.
catch :email_sent do
already_sent?
end
end
end
def already_sent?
# ...
end
def a_s_helper(label)
# ...
throw :email_sent if card::card_labels.include? label
# ...
end
您可能会想使用选项 2,因为它不需要对方法构造进行仔细控制,但它非常接近被广泛认为是反模式的 exceptions as flow control(它本质上是一个稍微更花哨的 GOTO,这因使代码难以阅读和调试而臭名昭著)。如果你可以简单地 return 从你的助手那里得到一个状态并决定是否继续循环,你应该这样做。
我想展示我是如何最终为看到这个问题的人实施从@Chris-heald 那里得到的解决方案的。我让它更紧凑一点。这是我最终使用的代码:
def card_handler
cards.each do |card|
real_id?
puts "real_id? : #{real_id?}"
next if !(real_id?)
needs_email?
puts "needs_email? : #{needs_email?}"
next if !(needs_email?)
get_email_info
end
end
def needs_email?
case list_action
when 147
!(card::card_labels.include? p1_label::id)
when 146
!(card::card_labels.include? p2_label::id)
when 145
!(card::card_labels.include? p3_label::id)
else
false
end
end
def real_id?
id != 0 ? true : false
end
def get_email_info
#more stuff
end
我有一系列嵌套的 each
循环遍历卡片列表。这些循环调用其他子函数,测试是否满足某些条件以便继续。
def card_handler
cards.each do |card|
#some non-relevant code is here on my end
already_sent?
end
end
def already_sent?
# allows for checking if different emails have been sent on the same card
if list_action == 147
a_s_helper(p1_label)
elsif list_action == 146
a_s_helper(p2_label)
elsif list_action == 145
a_s_helper(p3_label)
end
end
def a_s_helper(label)
if card::card_labels.include? label
# if the card already has the label, I want to log the error and return all the way to the next card in the iteration
puts '\n Order info: \n id: #{id} \n Email already sent'
next
# doesn't work
else
real_id?
end
end
就像我在 a_s_helper 的评论中所说的那样,如果卡片已经有标签,我想记录错误并 return 一直到迭代中的下一张卡片。我从当前设置中收到“下一个无效”错误。
有没有办法 return 一个 next
回到父函数或循环?
next
仅在循环的直接上下文中有效。一旦你调用了一个方法,你就不再直接处于那个循环上下文中。您不能像这样使用 next 来短路外环。
您有两个选择:
- Return 来自谓词函数的状态(这是你应该做的,来自谓词!)并基于这些使循环短路,或者
- 使用 Ruby 的
catch...throw
构造(这不是它的 raise/rescue 异常处理程序,而是 something like a block-scoped GOTO statement)
选项 1:Return查看状态。这是最合适的方法,IMO。谓词方法(那些以 ? 结尾的方法)通常应该 return 布尔值并且是幂等的(也就是说,应该没有副作用,例如记录语句)。它们通常用于提出 yes/no 问题。根据这个问题决定做什么最好不在他们的范围之内。
def card_handler
cards.each do |card|
#some non-relevant code is here on my end
if already_sent?
puts '\n Order info: \n id: #{id} \n Email already sent'
next
end
end
end
def already_sent?
case list_action
when 145
a_s_helper(p3_label)
when 145
a_s_helper(p2_label)
when 147
a_s_helper(p1_label)
end
end
def a_s_helper(label)
card::card_labels.include? label
end
这会导致您的助手 return 循环的真值或假值,它可以决定记录消息并转到下一次迭代。
选项 2:catch...throw
def card_handler
cards.each do |card|
# Put all your code that should nomally run inside the catch block. If
# the message :email_sent is thrown, then Ruby will zip up the stack and
# resume execution at the end of the block. This will skip any unexecuted
# code in the block, essentially terminating the execution.
catch :email_sent do
already_sent?
end
end
end
def already_sent?
# ...
end
def a_s_helper(label)
# ...
throw :email_sent if card::card_labels.include? label
# ...
end
您可能会想使用选项 2,因为它不需要对方法构造进行仔细控制,但它非常接近被广泛认为是反模式的 exceptions as flow control(它本质上是一个稍微更花哨的 GOTO,这因使代码难以阅读和调试而臭名昭著)。如果你可以简单地 return 从你的助手那里得到一个状态并决定是否继续循环,你应该这样做。
我想展示我是如何最终为看到这个问题的人实施从@Chris-heald 那里得到的解决方案的。我让它更紧凑一点。这是我最终使用的代码:
def card_handler
cards.each do |card|
real_id?
puts "real_id? : #{real_id?}"
next if !(real_id?)
needs_email?
puts "needs_email? : #{needs_email?}"
next if !(needs_email?)
get_email_info
end
end
def needs_email?
case list_action
when 147
!(card::card_labels.include? p1_label::id)
when 146
!(card::card_labels.include? p2_label::id)
when 145
!(card::card_labels.include? p3_label::id)
else
false
end
end
def real_id?
id != 0 ? true : false
end
def get_email_info
#more stuff
end