コンテンツへスキップ

as

as擬似メソッドは式の型を制限します。例えば

if some_condition
  a = 1
else
  a = "hello"
end

# a : Int32 | String

上記のコードでは、aInt32 | Stringのユニオンです。もし何らかの理由でifの後でaInt32であると確信できる場合、コンパイラにInt32として扱うように強制することができます。

a_as_int = a.as(Int32)
a_as_int.abs # works, compiler knows that a_as_int is Int32

as擬似メソッドはランタイムチェックを実行します。もしaInt32でなかった場合、例外が発生します。

式の引数はです。

ある型が別の型で制限されることが不可能な場合、コンパイル時エラーが発行されます。

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) }