as¶
as
伪方法限制表达式的类型。例如
if some_condition
a = 1
else
a = "hello"
end
# a : Int32 | String
在上面的代码中,a
是 Int32 | String
的联合类型。如果出于某种原因,我们确定 a
在 if
之后是一个 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) }