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
は他の言語のキャスト
のようなものではありません。整数、浮動小数点数、および文字のメソッドは、これらの変換のために提供されています。または、以下で説明するようにポインタキャストを使用してください。
ポインタ型間の変換¶
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) }