【问题标题】:Ruby evaluates the default value in fetch even when key is found即使找到键,Ruby 也会评估 fetch 中的默认值
【发布时间】:2020-03-28 20:49:43
【问题描述】:
h = {a: "foo"}
h.fetch(:a, h.fetch(:b))

收益key not found: :b

即使找到键,Ruby 也会评估默认值,这似乎很奇怪?有没有办法解决这个问题?

编辑: 显然,这种行为属于惰性与急切评估的范式。几乎所有命令式语言都使用急切求值,而许多函数式语言使用惰性求值。然而,某些语言,例如 Python(上周之前是我知道的唯一语言),对某些操作具有惰性求值能力。

【问题讨论】:

  • 在大多数语言中,函数参数不会被延迟计算。
  • @CollinD:该答案不适用/重复。如果fetch 不接受块/进程,则不能将其更改为这样做。
  • 我觉得你觉得很奇怪很奇怪,因为 Ruby 中的所有方法都是这样,事实上所有主流语言都是这样。你的第一语言是什么?哈斯克尔?
  • Python 不会那样做,至少 dict 的 get 方法不会。

标签: ruby


【解决方案1】:

即使找到键,Ruby 也会评估默认值,这似乎很奇怪?有没有办法解决这个问题?

绝大多数主流编程语言都是严格的,即参数在被传递之前要经过全面评估。唯一的例外是 Haskell,称其为主流有点牵强。

所以,不,这并不是真的“奇怪”,它是(几乎)每种语言的工作方式,也是 Ruby 中所有其他方法的工作方式。 Ruby 中的Every 方法总是 完全评估所有 其参数。也就是说,为什么 defined?alias 不能是方法,而必须是内置语言结构。

但是,有一种方法可以延迟评估,可以说是使用块:块的内容仅在每次调用时才评估。谢天谢地,Hash#fetch 确实占用了一个块,所以你可以使用

h.fetch(:a) { h.fetch(:b) }

【讨论】:

  • 另外,作为变体:h.fetch(:a, h.fetch(:b, '')) :)(我知道这是不对的,但是..)
【解决方案2】:

如果您希望仅在未找到密钥时运行计算,您可以使用接受块的fetch 的替代形式:

h.fetch(a) { h.fetch b }

我实际上并不知道是这种情况,但我有预感并尝试了它并且它起作用了。我想尝试这样做的原因是可以在其他方法(例如 gsub)中完成类似的操作,即

  "123".gsub(/[0-9]/) { |i| i.to_i + 1 } == "234"

【讨论】:

    【解决方案3】:

    您可以改用 || 运算符,因为它是惰性计算设计的。

    例如下面的代码没有定义Nope 不会抛出错误。

    { a: "foo" }[:a] || Nope
    

    但是 fetch 版本会抛出错误。

    { a: "foo" }.fetch(:a, Nope)
    

    我个人更喜欢fetch 的设计方式,因为它不会隐藏默认值中的错误。

    但是,如果我不想评估默认语句,那么在块或 lambda/proc 中执行某些操作之前,我肯定会使用 || 运算符。

    【讨论】:

    • || 如果左侧可以返回false,则运算符将无法解决问题。在这种情况下,您不知道是否找到了密钥
    猜你喜欢
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    相关资源
    最近更新 更多