跳到內容

型別自動轉換

當不存在歧義時,Crystal 會透明地轉換某些型別的元素。

數值自動轉換

如果沒有精度損失,數值型別的值會自動轉換為更大的型別

def foo(x : Int32) : Int32
  x
end

def bar(x : Float32) : Float32
  x
end

def bar64(x : Float64) : Float64
  x
end

foo 0xFFFF_u16 # OK, an UInt16 always fit an Int32
foo 0xFFFF_u64 # OK, this particular UInt64 fit in an Int32
bar(foo 1)     # Fails, casting an Int32 to a Float32 might lose precision
bar64(bar 1)   # OK, a Float32 can be autocasted to a Float64

當字面值的實際值符合目標型別時,無論其型別為何,數值字面值都會被自動轉換。

除非將 no_number_autocast 標誌傳遞給編譯器(請參閱編譯器功能),否則表達式會被轉換(如上面的最後一個範例所示)。

如果有歧義,例如,因為有多個選項,編譯器會拋出錯誤

def foo(x : Int64)
  x
end

def foo(x : Int128)
  x
end

foo 1_i32 # Error: ambiguous call, implicit cast of Int32 matches all of Int64, Int128

目前,自動轉換僅適用於兩種情況:函數呼叫(如目前所示)以及類別/實例變數初始化。以下範例顯示了實例變數的兩種情況範例:初始化時的轉換有效,但賦值時的轉換無效

class Foo
  @x : Int64 = 10 # OK, 10 fits in an Int64

  def set_x(y)
    @x = y
  end
end

Foo.new.set_x 1 # Error: "at line 5: instance variable '@x' of Foo must be Int64, not Int32"

符號自動轉換

符號會自動轉換為列舉成員,因此能夠以更簡潔的方式撰寫它們

enum TwoValues
  A
  B
end

def foo(v : TwoValues)
  case v
  in TwoValues::A
    p "A"
  in TwoValues::B
    p "B"
  end
end

foo :a # autocasted to TwoValues::A