我有一个我喜欢的特定方法,因为它可以让我决定是否要使用默认值。如果需要其他设置,请输入:option => value,否则将使用默认设置。这是一个可行的具体示例,但有点难看。

如何以更优雅的方式完成同一件事?

def connect_to_oracle opts = {}
  host_name = opts[:host_name]
  host_name ||= 'a_default_host_name'
  db_name = opts[:db_name]
  db_name ||= 'a_default_db_name'
  userid = opts[:userid]
  userid ||= 'a_default_userid'
  password = opts[:password]
  password ||= 'a_default_password'
  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end


#1 楼

您不需要||=即可使用||

def connect_to_oracle( opts = {} )
  host_name = opts[:host_name] ||'a_default_host_name'
  db_name = opts[:db_name] || 'a_default_db_name'
  userid = opts[:userid] || 'a_default_userid'
  password = opts[:password] ||'a_default_password'

  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end


另一种方法是Hash.merge

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( opts = {} )
  opts = DEFAULT.merge(opts)

  host_name = opts[:host_name]
  db_name = opts[:db_name]
  userid = opts[:userid]
  password = opts[:password]

  url = "jdbc:oracle:thin:#{userid}/#{password}@#{host_name}:1521:#{db_name}"
  $db = Sequel.connect(url)
end


or:

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( interface_opts = {} )
  opts = DEFAULT.merge(interface_opts )

  url = "jdbc:oracle:thin:%s/%s@%s:1521:%s" % [
    opts[:userid],
    opts[:password],
    opts[:host_name],
    opts[:db_name],
    ]
  $db = Sequel.connect(url)
end
connect_to_oracle()
connect_to_oracle(:host_name => :xxxxxxxx)


我更喜欢merge的版本。因此,我在文档中得到了带有所有默认参数的常量。

另一个优点:我可以轻松地添加检查接口中是否包含正确的键。

示例:

DEFAULT = {
  host_name: 'a_default_host_name',
  db_name:  'a_default_db_name',
  userid: 'a_default_userid',
  password: 'a_default_password',
}

def connect_to_oracle( myopts = {} )
  (myopts.keys - DEFAULT.keys).each{|key|
    puts "Undefined key #{key.inspect}"
  }
  opts = DEFAULT.merge(myopts)

  url = "jdbc:oracle:thin:%s/%s@%s:1521:%s" % [
    opts[:userid],
    opts[:password],
    opts[:host_name],
    opts[:db_name],
    ]
  #~ $db = Sequel.connect(url)
end
connect_to_oracle(:host_nam => :xxxxxxxx)


我的方法调用包含错误(忘记了'e'),但是调用它时,会收到警告Undefined key host_nam。这通常有助于检测错误。 (在实际情况下,我用记录器警告/错误替换了看跌期权)。

评论


\ $ \ begingroup \ $
.dup.update也可以表示为.merge。
\ $ \ endgroup \ $
–韦恩·康拉德
2014年1月10日20:35

\ $ \ begingroup \ $
@WayneConrad谢谢。我过去曾经使用过它,但似乎又忘记了它。我调整了答案。
\ $ \ endgroup \ $
–坚果
2014年1月10日20:45

\ $ \ begingroup \ $
要非常小心使用key = ops [:key] ||的布尔哈希参数。默认值,如果您尝试传递false,它将始终为默认值。解决它的一种方法是像key = ops [:key] .nil吗? ? true:ops [:key],您可以尝试通过假设如果它们传入该键将是false而不是默认值来缩短此时间,但是您将冒着风险,他们传入与默认值相同的值(假设它是真的),并且您错误地将其假定为假。您还可以反转您的值,因此默认值为false而不是true,但可读性较差。
\ $ \ endgroup \ $
– CTS_AE
18年1月8日在23:42

#2 楼

对于较新的红宝石版本,因为Ruby 2.1关键字参数是最好的选择。

def initialize(person:, greeting: "Hello")
end


这里,不需要问候语时必须有人。如果不传递人,则会得到一个ArgumentError: missing keyword: person

用关键字参数调用方法的语义与哈希相同。

Greeter.new(greeting: "Hey", person: "Mohamad")



对于旧版本的ruby

对于旧版本的Ruby(2.1版之前),可以使用访存fetch

使用fetch有两个优点:


它可以设置默认值
如果不指定默认值,则会引发错误

def initialize(options = {})
  @greeting = options.fetch(:greeting, "Hello")
  @person = options.fetch(:person)
end


如果您尝试在不传递:person的情况下实例化对象,则Ruby将引发错误。而:greeting将默认为hello。

#3 楼

在原始Ruby中,可以使用Hash#merge。由于参数hash中的键将获胜,因此您可以这样编写:

opts = {host_name: "a_default_host_name", db_name: "a_default_db_name"}.merge(opts)


如果使用Rails框架,则可以使用非常方便且优雅的Hash#reverse_merge!方法可编辑var本身(就像爆炸一样提醒您)

opts.reverse_merge!(host_name: "a_default_host_name", db_name: "a_default_db_name")


注意:您可以使用Active Support扩展(非常有用的小软件来改进Ruby),而无需使用所有的Rails框架,只需加载所需的扩展,在这种情况下,它将是:

require 'active_support/core_ext/hash/reverse_merge'


来源:Rails指南

#4 楼

如果您使用的是Ruby 2.0或更高版本,则可以使用关键字参数非常干净地完成此操作。在过去(2.0之前的版本)中,我使用了自定义帮助程序方法来复制此功能。对帮助程序的调用如下所示:保留现有值不变。

有关Ruby> = 2.0中关键字参数的文档,请访问rdoc.org-Methods.rdoc