如何使Ruby函数像一个显式的'return'语句?

时间:2014-08-14 17:06:03

标签: ruby

我正在尝试使用Ruby方法做一些不寻常的事情。我想让 terminate 在下面的代码中表现得像一个显式的return语句:

def terminate(data)
  data.upcase
  #I want to put a command somewhere in this scope
end

def other_method
  data = "cow"
  terminate data
  data = "fox"
end

other_method

#Desired response
#> "COW"
#Actual response in everything that we try
#> "fox"

我希望other_method返回“COW”。具体来说,通过使'terminate'作为显式返回语句起作用。有什么我可以投掷/加注会做到这一点?或者其他一些hacky方式我可以强迫这种行为?


目前,在我们的代码中,我们总是使用(在大型代码库中经常更改它的很多很多实例):

return foo! param1, param2
return foo2! param1, param2
return foo3! param1, param2

我们想用以下内容替换它:

foo! param1, param2
foo1! param1, param2
foo2! param1, param2

foo没有别的办法!在我们的代码库中按设计使用。它基本上是语法糖。

3 个答案:

答案 0 :(得分:5)

在Ruby中,除非在方法的其他地方使用显式return语句,否则在方法中执行的最后一行是返回的内容。也许复杂性在你更简单的例子中迷失了,但是:你能将terminate的结果存储在变量中并返回吗?

def other_method
  data = "cow"
  result = terminate data
  data = "fox"
  result
end

答案 1 :(得分:3)

  

在Ruby中,除非你在你的其他地方使用显式的return语句   方法,你的方法的最后一行是返回的。

这是不正确的。

  

我们尝试的所有内容的实际响应=> “狐狸”

没有显式return语句的ruby方法返回执行的最后一个语句的结果。这是在您的方法中执行的最后一个语句:

data = "fox"

并且赋值语句的“结果”是右侧,因此您的方法返回'fox'。如果该行总是在您的方法中执行的最后一行,您的方法将始终返回'fox'。

对评论的回应:

你可以这样做(但我看不出它会对你有什么帮助):

def other_method
  data = "cow"

  func = Proc.new {|data| return data.upcase}
  func[data]

  data = "fox"
end

puts other_method

--output:--
COW

但你不能这样做:

def other_method(func)
  data = "cow"

  func[data]

  data = "fox"
end

f = Proc.new { |data| return data.upcase }
other_method(f)

--output:--
unexpected return (LocalJumpError)

...

Is there something I can throw / raise that will do this?

是的,你可以这样做:

class MyTerminateMethodError < Exception
end

def terminate(d)
  raise MyTerminateMethodError, d.upcase
end


def other_method
  data = "cow"
  terminate data
  data = "fox"
rescue MyTerminateMethodError => result
  result   #This is the last statement to execute, so result is returned
end

puts other_method

--output:--
COW

但事实是,将数据传递给terminate()方法没有任何好处,因为你可以这样做:

class MyTerminateMethodError < Exception
end

def terminate
  raise MyTerminateMethodError
end

def other_method
  data = "cow"
  terminate 
  data = "fox"
rescue MyTerminateMethodError
  data.upcase
end

puts other_method

相当于:

class MyTerminateMethodError < Exception
end

def other_method
  data = "cow"
  raise MyTerminateMethodError
  data = "fox"
rescue MyTerminateMethodError
  data.upcase
end

puts other_method

可以更有效地编写:

def other_method
  data = "cow"
  return data.upcase
  data = "fox"
end

好的,但您希望将不同的行为应用于数据 - 而不仅仅是upcase()?一块怎么样?

def other_method
  data = "cow"

  if block_given?
    return (yield data)
  end

  data = "fox"
end

result = other_method { |x| x.capitalize }
puts result  =>Cow

如果您无法更改other_method(),那么您可以这样做:

class MyTerminateMethodError < Exception
end

def terminate(d)
  raise MyTerminateMethodError, d.upcase
end


def other_method
  data = "cow"
  terminate data
  data = "fox"
end

result = begin 
  other_method
rescue MyTerminateMethodError => str 
end

puts result   #=>COW

答案 2 :(得分:2)

throw / catch会这样做。

在调用Kernel#catch

时,将您方法的内容包裹起来
def something
  catch :return do
    foo! 123, 456
  end
end

#foo!来电Kernel#throw

def foo!(*args)
  throw :return, args
end

调用#throw时,会导致异常被#catch语句捕获。然后#catch语句的结果是赋予#throw语句的值。因此:

p something     # [123, 456]

如果未调用#throw,则#catch的结果是其块中执行的最后一个语句的结果。