1

我想在递归调用期间保持变量的值静态,例如,如果foo是一个name作为参数的函数,我想将name 第一次调用的值保存foo在一个变量中,并且该变量将在每个变量中保留该值对 foo 的递归调用。

def run_app (name, startr)
  if startr==1
    constant_var=name
  end

  some_name = modify name
  diff = compare some_name, constant_var

  # recursive call
  run_app some_name, 0
end

第一次调用就像,run_app "john", 1我希望在调用期间保留 constant_var 的值。我怎样才能做到这一点?

4

3 回答 3

5

首先,您的代码中有一些冗余。diff已分配但从未使用过。你可以摆脱它:

def run_app(name, startr)
  constant_var = name if startr == 1

  some_name = modify name
  compare(some_name, constant_var)

  # recursive call
  run_app(some_name, 0)
end

解决这个问题的标准方法是添加一个额外的参数来传递额外的信息:

def run_app(name, startr, constant_var)
  some_name = modify name
  compare(some_name, constant_var)

  # recursive call
  run_app(some_name, 0, constant_var)
end

然后你需要像这样调用方法:

run_app(tmp = 'john', 1, tmp)

# or

run_app('john', 2, nil)

但是,这会将大量内部实现细节泄露给调用者,并给他们带来沉重的负担。例如,他们需要知道第一个和第三个参数必须是同一个对象。但前提是它们1作为第二个参数传递。如果它们传递的不是1,那么它们需要nil作为第三个参数传递。

什么可以阻止某人打电话

run_app('john', 1, 'ringo')

# or 

run_app(tmp = 'john', 2, tmp)

您可以通过使用带有默认参数的可选参数来稍微改进:

def run_app(name, startr, constant_var = name if startr == 1)
  some_name = modify name
  compare(some_name, constant_var)

  # recursive call
  run_app(some_name, 0, constant_var)
end

现在你可以像你想要的那样调用它:

run_app('john', 1)

# or

run_app('john', 2)

但是,您仍然可以这样称呼它:

run_app('john', 1, 'ringo')

# or 

run_app(tmp = 'john', 2, tmp)

所以,我们要做的就是将该逻辑移到private辅助方法中,并为公共方法提供我们想要的 API:

def run_app(name, startr)
  constant_var = name if startr == 1

  run_app_r(name, startr, constant_var)
end

private

def run_app_r(name, startr, constant_var)
  some_name = modify name
  compare(some_name, constant_var)

  # recursive call
  run_app_r(some_name, 0, constant_var)
end

像这样称呼它:

run_app('john', 1)

# or

run_app('john', 2)

当然,您现在仍然可以调用

run_app_r('john', 1, 'ringo')

# or 

run_app_r(tmp = 'john', 2, tmp)

但至少你现在有一个单独的方法,你可以清楚地记录为private,例如通过使用 YARD 的@private标签或只使用 RDoc 的:nodoc:标签将其完全排除在文档之外。

run_app_r方法可以从任何地方调用,即使它只是在内部调用,这一事实run_app非常烦人。在像 Scala 这样支持嵌套方法的语言中,您只需将run_app_r方法放在方法内部run_app,但 Ruby 不支持嵌套方法,因此我们必须找到另一种方法:Procs 可以嵌套在方法内部!

def run_app(name, startr)
  constant_var = name if startr == 1

  (run_app_r = ->(name, startr, constant_var; some_name) {
    some_name = modify name
    compare(some_name, constant_var)

    # recursive call
    run_app_r.(some_name, 0, constant_var)
  }).(name, startr, constant_var)
end

像这样称呼它:

run_app('john', 1)

# or

run_app('john', 2)

由于块是闭包,我们甚至不需要显式传递constant_var

def run_app(name, startr)
  constant_var = name if startr == 1

  (run_app_r = ->(name, startr; some_name) {
    some_name = modify name
    compare(some_name, constant_var)

    # recursive call
    run_app_r.(some_name, 0)
  }).(name, startr)
end

像这样称呼它:

run_app('john', 1)

# or

run_app('john', 2)

但这一切都没有实际意义,因为您的递归没有基本情况,因此将无限循环。或者更确切地说,您将得到堆栈溢出,因为 Ruby 不保证正确的尾调用。

于 2013-08-15T10:36:52.993 回答
0

我会使用修改后的名称的参数:

def run_app (name, modified_name=name)
  # do something with name
  modified_name = modify(name)

  # recursive call
  run_app name, modified_name
end

然后,您可以只调用该方法run_app("John")

于 2013-08-15T08:41:36.027 回答
0

一种方法是为您的递归调用编写一个包装器,该包装器在调用实际函数之前将变量存储在某处。也许作为您班级的成员变量。

def run_wrapper(name, startr)
    @orig_name = name

    run_app (name, startr)
end

def run_app(name, startr)
    p @orig_name
end

更简洁的方法可能是添加第三个参数

def run_app(name, startr, orig_name = nil)
    ...
    run_app("blah", startr-1, orig_name || name)
end
于 2013-08-15T08:44:28.143 回答