Введите псевдоним и хэш в качестве параметра метода

Я пытаюсь создать инициализатор для класса, который получает параметр Hash as. Хеш - это хеш {String => Type}, который может быть вложенным. Я получаю сообщение об ошибке при запуске этого кода:

#file: types.cr
class Types
  alias Type = Nil |
               Bool |
               Int32 |
               Int64 |
               Float64 |
               String |
               Array(Type) |
               Hash(String, Type)

  def initialize(@input : Type)
  end
end

input = {"a" => {"b" => {"c" => {"c1" => 1, "c2" => 2, "c3" => true}}}}
s = Types.new(input)

Вот ошибка, которую я получаю при запуске кода выше:

$ crystal types.cr

Error in types.cr:16: instantiating 'Types:Class#new(Hash(String, Hash(String, Hash(String, Hash(String, Bool | Int32)))))'

s = Types.new(input)
          ^~~

in types.cr:11: instance variable '@input' of Types must be Types::Type, not Hash(String, Hash(String, Hash(String, Hash(String, Bool | Int32))))

  def initialize(@input : Type)
                 ^~~~~~

Возможно ли это с Кристаллом? Как мне подойти к этому?

Спасибо!


person Matias    schedule 07.09.2017    source источник


Ответы (1)


Вы можете сделать это, указав тип каждого хеша:

c = {"c1" => 1, "c2" => 2, "c3" => true} of String => Types::Type
b = {"c" => c} of String => Types::Type
a = {"b" => b} of String => Types::Type

t = Types.new({"a" => a} of String => Types::Type)
pp t # => #<Types:0x103085ec0
     #    @input=
     #      {"a" => {"b" => {"c" => {"c1" => 1, "c2" => 2, "c3" => true}}}}>

Другой подход - определить и использовать хеш-подобный тип:

alias Type = Nil         |
             Bool        |
             Int32       |
             Int64       |
             Float64     |
             String      |
             Array(Type) |
             Hash(String, Type)

alias TypesHash = Hash(String, Type)

t = TypesHash{
  "a" => TypesHash{
    "b" => TypesHash{
      "c" => TypesHash{
        "c1" => 1, "c2" => 2, "c3" => true,
      },
    },
  },
}

t                                            # {"a" => {"b" => {"c" => {"c1" => 1, "c2" => 2, "c3" => true}}}}
t["a"]                                       # {"b" => {"c" => {"c1" => 1, "c2" => 2, "c3" => true}}}
t["a"].as(TypesHash)["b"]                    # {"c" => {"c1" => 1, "c2" => 2, "c3" => true}}
t["a"].as(TypesHash)["b"].as(TypesHash)["c"] # {"c1" => 1, "c2" => 2, "c3" => true}

Таким образом, вы можете передать его конструктору точно так же, как объект TypesHash:

class Types
  def initialize(@input : TypesHash); end
end

Types.new t
person Vitalii Elenhaupt    schedule 07.09.2017