如何在“if”语句中使用联合(Union)[Crystal]

3
以下代码可以正常工作并打印出“5.0”。
$x : Float64
$y : Float64
$x = 3.0_f64
$y = 2.0_f64
puts $x + $y

现在,我改变了代码以支持“nil”。

$x : Float64?
$y : Float64?
$x = 3.0_f64
$y = 2.0_f64
puts $x + $y if !$x.nil? && !$y.nil?

然而,此代码报告以下错误信息。
没有重载与类型(Float64 | Nil)匹配的'Float64 #+'。
重载是:
- Float64#+(other : Int8)
- Float64#+(other : Int16)
- Float64#+(other : Int32)
- Float64#+(other : Int64)
- Float64#+(other : UInt8)
- Float64#+(other : UInt16)
- Float64#+(other : UInt32)
- Float64#+(other : UInt64)
- Float64#+(other : Float32)
- Float64#+(other : Float64)
- Number#+()
找不到这些类型的重载:
- Float64#+(Nil)
如果$x或$y为空,则停止调用方法“#+()”,如果两者都为Float64,则打印计算结果。
在这种情况下,最佳实践是什么?
在上面的代码中,我简化了此问题的代码。但结果意外地改变了问题的含义。实际上,我想问以下代码。
class Xyz
  property a, b
  @a : Float64?
  @b : Float64?

  def initialize
    @a = nil
    @b = nil
  end

  def do_calc
    if !@a.nil? && !@b.nil?
      puts @a + @b
    else
      puts "We can't calculate because '@a or @b has nil."
    end
  end
end

x = Xyz.new
x.a = 3.0_f64
x.b = 2.0_f64
x.do_calc

这段代码报告了以下错误。

正在实例化'Xyz#do_calc()'
x.do_calc ^~~~~~~
在./a.cr:15中:没有重载与类型(Float64 | Nil)匹配的'Float64#+'。 重载是:  - Float64#+(other:Int8)  - Float64#+(other:Int16)  - Float64#+(other:Int32)  - Float64#+(other:Int64)  - Float64#+(other:UInt8)  - Float64#+(other:UInt16)  - Float64#+(other:UInt32)  - Float64#+(other:UInt64)  - Float64#+(other:Float32)  - Float64#+(other:Float64)  - Number#+() 找不到这些类型的重载:  - Float64#+(Nil)
 puts @a + @b

如何避免这个错误?

2个回答

4

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - elgoog
我在你指定的链接中找到了答案。抱歉问题重复了。 - elgoog

0

我认为这是由于编译器无法推断出if子句内部的类型,它并不像动态类型语言那样。如果@a类型是Nil怎么办?我们没有+运算符适用于Nil类型。因此,您必须显式地声明@a@bFloat64

class Xyz
  property a, b
  @a : Float64?
  @b : Float64?

  def initialize
    @a = nil
    @b = nil
  end

  def do_calc
    if !@a.nil? && !@b.nil?
      puts @a.as(Float64) + @b.as(Float64)
    else
      puts "We can't calculate because '@a or @b has nil."
    end
  end
end

x = Xyz.new
x.a = 3.0_f64
x.b = 2.0_f64
x.do_calc

或者使用从Object抽象类派生的#try(Float和Nil也是它的派生类)

class Xyz
  property a, b
  @a : Float64?
  @b : Float64?

  def initialize
    @a = nil
    @b = nil
  end

  def do_calc
    if !@a.nil? && !@b.nil?
      @a.try do |a|
        @b.try do |b|
          puts a + b
        end
      end
    else
      puts "We can't calculate because '@a or @b has nil."
    end
  end
end

x = Xyz.new
x.a = 3.0_f64
x.b = 2.0_f64
x.do_calc

最佳实践

这取决于你。对我来说,它取决于上下文。我认为使用#try更好,因为它更明确,它解释了一个变量可能是nil类型。但在这种情况下,使用#try会很啰嗦,所以我会选择第一种解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接