as¶
as
虛擬方法限制了表達式的型別。例如
if some_condition
a = 1
else
a = "hello"
end
# a : Int32 | String
在上面的程式碼中,a
是 Int32 | String
的聯合型別。如果由於某些原因,我們確定在 if
之後 a
是 Int32
,我們可以強制編譯器將其視為 Int32
a_as_int = a.as(Int32)
a_as_int.abs # works, compiler knows that a_as_int is Int32
as
虛擬方法會執行執行階段檢查:如果 a
不是 Int32
,則會拋出例外。
表達式的引數是型別。
如果無法使用另一型別限制某型別,則會發出編譯時期錯誤
1.as(String) # Compile-time error
注意
您無法使用 as
將型別轉換為不相關的型別:as
不像其他語言中的 cast
。整數、浮點數和字元的方法提供了這些轉換。或者,使用如下所述的指標轉換。
指標型別之間的轉換¶
as
虛擬方法也允許在指標型別之間進行轉換
ptr = Pointer(Int32).malloc(1)
ptr.as(Int8*) # :: Pointer(Int8)
在這種情況下,不會執行執行階段檢查:指標是不安全的,這種型別的轉換通常僅在 C 綁定和底層程式碼中需要。
指標型別和其他型別之間的轉換¶
指標型別和參考型別之間的轉換也是可能的
array = [1, 2, 3]
# object_id returns the address of an object in memory,
# so we create a pointer with that address
ptr = Pointer(Void).new(array.object_id)
# Now we cast that pointer to the same type, and
# we should get the same value
array2 = ptr.as(Array(Int32))
array2.same?(array) # => true
在這些情況下不會執行執行階段檢查,因為同樣地,涉及到指標。這種轉換的需求比前一種更為罕見,但允許在 Crystal 本身中實作一些核心型別(例如 String),並且也允許通過將參考型別轉換為 void 指標來將其傳遞給 C 函數。
用於轉換為較大型別的用法¶
as
虛擬方法可用於將表達式轉換為「較大」的型別。例如
a = 1
b = a.as(Int32 | Float64)
b # :: Int32 | Float64
以上似乎沒有用,但當例如映射元素陣列時,它會很有用
ary = [1, 2, 3]
# We want to create an array 1, 2, 3 of Int32 | Float64
ary2 = ary.map { |x| x.as(Int32 | Float64) }
ary2 # :: Array(Int32 | Float64)
ary2 << 1.5 # OK
Array#map
方法使用區塊的型別作為陣列的泛型型別。如果沒有 as
虛擬方法,推斷的型別將為 Int32
,並且我們將無法在其中加入 Float64
。
用於編譯器無法推斷區塊型別的情況¶
有時編譯器無法推斷區塊的型別。這種情況可能會發生在相互依賴的遞迴呼叫中。在這種情況下,您可以使用 as
來使其知道型別
some_call { |v| v.method.as(ExpectedType) }