Rails 小技巧(三) - 使用 fetch 获取 Hash 和 Array 中的值

环境

  • Ruby: 3.0.1
  • Ruby On Rails: 6.1.4

什么是 fetch

方法签名:

fetch(key[, default]) -> obj
fetch(key){ |key| block } -> obj

使用:

h = {}

h.fetch(:a) # => KeyError: key not found: :a
h.fetch(:a, 1)  # => 1
h.fetch(:a){ 1 }    # => 1
h.fetch(:a, :1){ 2 }    # => 2   同时会有一个 warning 提示 block 覆盖了 default

h.fetch(:a){ |key| "#{key}: 2" }    # => "a: 2"

# 还可以自定义找不到 key 时的操作
h.fetch(:a) do |key|
    raise ArgumentError, "key #{key} not found" # => ArgumentError: key a not found
end

下面是Rubydoc关于fetch的描述

从 hash 中获取给定的 key 对应的值。如果没有找到该 key,那么有以下几种情况会发生:没有传入其他参数时,抛出KeyError的异常;如果指定了default,则返回default;如果给定了块,则会运行块并返回块的返回值;同时有default和块时,块会覆盖掉default

对于数组的用法也是类似的,只是key被替换成了index,还有就是index不存在时抛出的异常类型是IndexError而不是KeyError

arr = []

arr.fetch(0)    # => IndexError: index 0 outside of array bounds: 0...0
arr.fetch(0, 1) # => 1
arr.fetch(0){ 1 }   # => 1
arr.fetch(0, 1) { 2 }   # => 2  同时会有一个 warning 提示 block 覆盖了 default

fetch 中使用 default 和块指定默认值的区别

  1. 首先是优先级的问题,上面已经指出块的优先级是高于default参数的
  2. 不管是否有找到值,default都会先求值(如果default是方法或其他可以执行的代码),而代码块是惰性求值的,也就是说块只有在找不到key的情况下才会触发。

fetch 和 [] 取值方式的不同

  1. fetchkey不存在时会抛出KeyError或者是IndexError的异常,而[]只会返回nil。这点可以用在强制要求key存在的情况
  2. fetch可以指定默认值,不管是通过default还是block

其他应用场景

假设要获取配置中的 database 中的 host ,如果没有则使用默认值

config = {}
config.fetch(:database, {}).fetch(:host, "127.0.0.1") 

仅供思维启发,实际上这样场景使用dig会更加直观

config.fetch(:database, :host) || "127.0.0.1"

关于dig的使用可以看 Rails 小技巧(二) - 使用 dig 获取嵌套 Hash 和 Array 的数据


参考

RubyDoc
《优雅的Ruby》


写在最后

文章内容错误的地方,欢迎及时指出。

最後までご覧いただいてありがとうございます


Rails 小技巧系列

点赞

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注