如何使用"如果"声明[水晶]

时间:2016-09-07 15:05:20

标签: crystal-lang

以下代码运作良好并打印" 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?

但是,此代码报告以下错误消息。

no overload matches 'Float64#+' with type (Float64 | Nil)
Overloads are:
 - 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#+()
Couldn't find overloads for these types:
 - Float64#+(Nil)

    puts $x + $y if !$x.nil? && !$y.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

此代码报告错误。

instantiating 'Xyz#do_calc()'

x.do_calc
  ^~~~~~~

in ./a.cr:15: no overload matches 'Float64#+' with type (Float64 | Nil)
Overloads are:
 - 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#+()
Couldn't find overloads for these types:
 - Float64#+(Nil)

      puts @a + @b

如何避免此错误?

2 个答案:

答案 0 :(得分:4)

请务必阅读有关if和检查nil的文档:https://crystal-lang.org/docs/syntax_and_semantics/if_var.htmlhttps://crystal-lang.org/docs/syntax_and_semantics/if_var_nil.html

这仅适用于局部变量,因此您需要首先将值分配给局部变量。

作为旁注,自Crystal 0.19.0起,全局变量不再存在于语言中。

答案 1 :(得分:0)

我认为发生这种情况是因为编译无法推断if子句中的类型,它不像动态类型的语言。如果@a类型是Nil怎么办?我们没有+类型的Nil运算符。因此,您声明@a@b明确是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.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

或使用从#try抽象类派生而来的Object(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非常冗长,因此我将寻求第一个解决方案。