【问题标题】:Passing a hash as an initial value when creating an object创建对象时将哈希值作为初始值传递
【发布时间】:2018-05-22 05:37:46
【问题描述】:

我正在创建一个 Temperature 类,其中包含将温度从 f 转换为 c 的实例方法,反之亦然。一个测试用例是:

Temperature.new(:f => 32).in_celsius #=> 0

我认为传递 :f => 32 会产生转换。我不知道如何从哈希:f => 32 中提取值32。我想提取它,以便我可以将该数字转换为 f 或 c。

下面是我的答案代码。

class Temperature      
  def initialize(f = 0, c = 0)
    @f = f
    @c = c 
  end

  def in_fahrenheit
    c = @c * 1.8
    c += 32
    @f = c.floor
    @f 
  end

  def in_celsius
    f = @f - 32
    f /= 1.8
    @c = f.floor
    @c 
  end

  def fahrenheit
    @f 
  end 

  def celsius
    @c 
  end
end

我不熟悉在创建对象时作为初始值传递的哈希值。如有任何建议,我将不胜感激。

【问题讨论】:

  • 有什么问题?
  • 我是 ruby​​ 新手,我的问题是传递哈希 :f => 32 对我来说也是新事物,我不知道如何提取该对中的值 (32)。我想知道如何提取它,以便我可以将该数字转换为 f 或 c。
  • 这是家庭作业吗?
  • 您也可以使用keyword arguments,它基本上是采用哈希参数并将属性分配给变量的简写。

标签: ruby


【解决方案1】:

您的initialize 方法正在寻找两个参数,但您的输入仅包含一个,即散列。以下是处理包含华氏度的哈希的方法:

  def initialize(temp)
    @f = temp[:f] 
  end

如果您想处理 F 或 C 中的输入,我将把它留给您作为练习。

【讨论】:

  • 如果我有两个参数,这是否适用?例如:def initialize(temp) @f = temp[:f] @c = temp[:c] end
  • 您可以拥有一个包含任意数量键的单一哈希。虽然老实说,当你的班级为你进行转换时,我不知道你为什么要接受包含 F C 的输入。
  • 等等什么意思?你的意思是我不需要def初始化?
【解决方案2】:

如果我是你,我想我会这样做:

class Temperature

  def initialize(input)
    puts "in #{self.class}.#{__method__}, input.class.name is: #{input.class.name}"
    @f, @c = input[:f], input[:c]
  end

  def in_fahrenheit
    return @f if @f
    c = @c * 1.8
    c += 32
    @f = c.floor
    @f 
  end

  def in_celsius
    return @c if @c
    f = @f - 32
    f /= 1.8
    @c = f.floor
    @c 
  end

  def fahrenheit
    return @f if @f
    in_fahrenheit
  end 

  def celsius
    return @c if @c
    in_celsius
  end

end

正如 Mark Thomas 所指出的,initialize 正在接收 Hash

> t = Temperature.new(f: 32)
in Temperature.initialize, input.class.name is: Hash
 => #<Temperature:0x0000000996cbf8 @f=32, @c=nil> 

顺便说一句,f: 32:f =&gt; 32 更现代一点,我相信。

我添加了一些return 语句。这样,您可以:

> t = Temperature.new(f: 32)
 => #<Temperature:0x00000009856ca0 @f=32, @c=nil> 
> t.fahrenheit
 => 32 
> t.celsius
 => 0 
> t.in_fahrenheit
 => 32
> t.in_celsius
 => 0 

还有:

> t = Temperature.new(c: 0)
 => #<Temperature:0x0000000986b038 @f=nil, @c=0> 
> t.fahrenheit
 => 32 
> t.celsius
 => 0 
> t.in_fahrenheit
 => 32 
> t.in_celsius
 => 0 

正如马克也说过,你可以这样做:

t = Temperature.new(f: 32, c: 32)

但是,这会给你带来各种错误的结果。所以,如果你想防止这种情况发生,你可以这样做:

class Temperature

  def initialize(input)
    puts "in #{self.class}.#{__method__}, input.class.name is:"<<" #{input.class.name}"
    @f, @c = input[:f], input[:c]
    raise "Only one input, please!" if @f and @c
  end

  def in_fahrenheit
    return @f if @f
    c = @c * 1.8
    c += 32
    @f = c.floor
    @f 
  end

  def in_celsius
    return @c if @c
    f = @f - 32
    f /= 1.8
    @c = f.floor
    @c 
  end

  def fahrenheit
    return @f if @f
    in_fahrenheit
  end 

  def celsius
    return @c if @c
    in_celsius
  end

end

这会给你类似的东西:

> t = Temperature.new(f: 32, c: 0)
in Temperature.initialize, input.class.name is: Hash
RuntimeError: Only one input, please!

【讨论】:

  • 感谢您的意见。当我得知可以使用哈希加键来获取值时,我就想通了。
  • 没问题。我只是在逃避自己的工作,TBH。希望不要太多。
【解决方案3】:

您错误地混合了不同的参数样式。

位置参数

从您的电话Temperature.new(:f =&gt; 32) 来看,您似乎认为def initialize(f = 0, c = 0) 提供哈希或关键字参数。它没有。这只是两个位置参数(具有默认值,因此它们是可选的)。让我们打印出来看看会发生什么:

  def initialize(f = 0, c = 0)
    puts "f is #{f.inspect}"
    puts "c is #{c.inspect}"
  end

您的电话:

Temperature.new(:f => 32)
f is {:f=>32}
c is 0

显然这不是您想要的,也是您稍后会收到错误的原因。以下是你必须如何称呼它:

Temperature.new(32)
f is 32
c is 0

Temperature.new(0, 32)
f is 0
c is 32

顺便说一句,nil 会比0 更好的默认值,因为0 是一个完全有效的温度。为了提供c 值而必须提供一些f 值是很糟糕的。

哈希参数

在上面我们看到 Ruby 为您创建了一个哈希,然后它成为该方法获得的参数。因此,您可以更改方法签名以反映这一点,即采用哈希,然后从中提取值:

  def initialize(options)
    f = options[:f]
    c = options[:c]
    puts "f is #{f.inspect}"
    puts "c is #{c.inspect}"
  end

现在您可以像以前一样使用它了:

Temperature.new(:f => 32)
f is 32
c is nil

Temperature.new(:c => 32)
f is nil
c is 32

请注意,通过这种方式,您确实会得到nil 作为默认值。你也可以使用这个更好的语法:

Temperature.new(f: 32)
f is 32
c is nil

Temperature.new(c: 32)
f is nil
c is 32

关键字参数

大约五年前,Ruby 2 came out and brought us keyword arguments。现在,除了为您创建散列之外,还可以告诉 Ruby 为您将其拆开。像这样:

  def initialize(f: nil, c: nil)
    puts "f is #{f.inspect}"
    puts "c is #{c.inspect}"
  end

你仍然可以像以前一样调用它:

Temperature.new(f: 32)
f is 32
c is nil

Temperature.new(c: 32)
f is nil
c is 32

initialize(f: nil, c: nil) 看起来不是比initialize(options) 更有意义吗?它甚至看起来很像现在的电话。而且您不需要额外的代码来从哈希中提取值。此外,如果您输入错误的参数名称,您现在会收到错误消息:

Temperature.new(x: 32)
ArgumentError: unknown keyword: x

单个哈希参数解决方案只需将fc 设置为nil 并愉快地继续前进,就好像没有问题一样。

顺便说一句,即使使用显式哈希和火箭符号,您仍然可以调用它,尽管我只是为了进一步理解而展示它:

Temperature.new({:f => 32})
f is 32
c is nil

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多