Spec-Zone.ru › Crystal

as

Псевдометод as ограничивает типы выражения. Например:

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

# a : Int32 | String

В приведённом выше коде a — это объединение Int32 | String. Если по какой-либо причине мы уверены, что после if a является 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 и низкоуровневом коде.

Преобразование между типами указателей и другими типами

Также возможно преобразование между типами указателей и типами Reference:

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

В этих случаях проверки во время выполнения не производятся, поскольку, опять же, используются указатели. Такая необходимость возникает ещё реже, чем в предыдущем случае, но это позволяет реализовывать некоторые основные типы (например, String) непосредственно на Crystal, а также передавать тип Reference в функции C, приводя его к указателю void.

Использование для приведения к более широкому типу

Псевдометод 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) }

To the extent possible under law, the persons who contributed to this workhave waived
all copyright and related or neighboring rights to this workby associating CC0 with it.
https://crystal-lang.org/reference/1.2/syntax_and_semantics/as.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API