Это работает:
module Thing
alias Ish = UInt8 | Array(Ish)
def self.decode(bytes : Bytes) : {Ish, Bytes}
case bytes[0]
when 0x00..0x17
{bytes[0], bytes + 1}
when 0x18
MultiItemDecoder.new(0x80, ->(x : Bytes) { Thing.decode(x) }).decode(bytes)
else
raise "unknown"
end
end
class MultiItemDecoder(T)
def initialize(@base : UInt8, @item_decoder : Bytes -> {T, Bytes})
end
def decode(bytes) : {Ish, Bytes}
decode_some(bytes + 1, bytes[0])
end
def decode_some(bytes, n)
items = n.times.map do
item, bytes = @item_decoder.call(bytes)
item.as(Ish)
end
{items.to_a.as(Ish), bytes}
end
end
end
Thing.decode(Bytes[1, 2, 3])
Дело в том, что Array(Array(Ish))
не является Array(Ish)
, потому что для этого оно должно быть Array(Array(Ish) | UInt8)
(обратите внимание, что это массив объединения).
Все это сводится к тому, как вещи представлены в памяти.
Мой совет - избегать использования рекурсивных псевдонимов. Они не интуитивно понятны, и мы могли бы в конечном итоге удалить их из языка.