在Java中,您可以重载构造函数:
public Person(String name) {
this.name = name;
}
public Person(String firstName, String lastName) {
this(firstName + " " + lastName);
}
Ruby中有没有办法实现同样的结果:两个构造函数采用不同的参数?
答案 0 :(得分:70)
答案是肯定和否。
您可以使用各种机制在其他语言中获得与您相同的结果,包括: -
该语言的实际语法不允许您定义两次方法,即使参数不同。
考虑到上面的三个选项,可以使用您的示例实现,如下所示
# As written by @Justice
class Person
def initialize(name, lastName = nil)
name = name + " " + lastName unless lastName.nil?
@name = name
end
end
class Person
def initialize(args)
name = args["name"] + " " + args["lastName"] unless args["lastName"].nil?
@name = name
end
end
class Person
def initialize(*args)
#Process args (An array)
end
end
你会经常在Ruby代码中遇到第二种机制,特别是在Rails中,因为它提供了两全其美的优点,并允许一些语法糖产生漂亮的代码,特别是不必将传递的哈希包含在大括号内。
此wikibooks link提供更多阅读
答案 1 :(得分:25)
我倾向于
class Person
def self.new_using_both_names(first_name, last_name)
self.new([first_name, last_name].join(" "))
end
def self.new_using_single_name(single_name)
self.new(single_name)
end
def initialize(name)
@name = name
end
end
但我不知道这是否是最佳方法。
答案 2 :(得分:4)
class Person
def initialize(name, lastName = nil)
name = name + " " + lastName unless lastName.nil?
@name = name
end
end
答案 3 :(得分:2)
class StatementItem
attr_reader :category, :id, :time, :amount
def initialize(item)
case item
when Order
initialize_with_order(item)
when Transaction
initialize_with_transaction(item)
end
end
def valid?
!(@category && @id && @time && @amount).nil?
end
private
def initialize_with_order(order)
return nil if order.status != 'completed'
@category = 'order'
@id = order.id
@time = order.updated_at
@amount = order.price
end
def initialize_with_transaction(transaction)
@category = transaction.category
@id = transaction.id
@time = transaction.updated_at
@amount = transaction.amount
end
end
答案 4 :(得分:1)
您可以使用konstructor gem在Ruby中声明多个构造函数并模仿重载:
class Person
def initialize(name)
@name = name
end
konstructor
def from_two_names(first_name, last_name)
@name = first_name + ' ' + last_name
end
end
Person.new('John Doe')
Person.from_two_names('John', 'Doe')
答案 5 :(得分:1)
您可以将 double splat运算符 **
与||
内的 logic或(双管道)initialize
结合使用达到相同效果的方法。
class Person
def initialize(**options)
@name = options[:name] || options[:first_name] << ' ' << options[:last_name]
end
end
james = Person.new(name: 'James')
#=> #<Person @name="James">
jill_masterson = Person.new(first_name: 'Jill', last_name: 'Masterson')
#=> #<Person @name="Jill Masterson">
但是,如果创建的新Person
不包含first_name
,则附加<<
操作将失败,并显示NoMethodError: undefined method '<<' for nil:NilClass
。这是一种重构的initialize
方法来处理这种情况(如果排除了 个选项,则使用strip
删除空格)。
class Person
def initialize(**options)
@name = options[:name] || [ options[:first_name] , options[:last_name] ].join(' ').strip
end
end
goldfinger = Person.new(last_name: 'Goldfinger')
#=> #<Person @name="Goldfinger">
oddjob = Person.new(first_name: 'Oddjob')
#=> #<Person @name="Oddjob">
实际上,此方法处理不带参数或使用意外键的Person.new
调用,以将@name
设置为空字符串返回新实例:
nameless = Person.new
#=> <#Person @name="">
middle_malcom = Person.new(middle_name: 'Malcom')
#=> <#Person @name="">
答案 6 :(得分:0)
我通常会这样做:
class Person
attr_reader :name
def initialize(first: nil, last: nil)
@name = [first, last].compact.join(' ')
end
end
Person.new(first: 'ya').name
# => "ya"
Person.new(first: 'ya', last: 'ku').name
# => "ya ku"
答案 7 :(得分:0)
结帐functional-ruby的宝石,它受Elixir pattern matching功能的启发。
class Foo include Functional::PatternMatching defn(:initialize) { @name = 'baz' } defn(:initialize, _) {|name| @name = name.to_s } end