2017-07-31 13 views
1

私は汎用ペイロードを受け入れ、その後、JSONに変換し、クラスを実装しようとしています:引数として汎用ハッシュ?

require "json" 

class Response 
    alias Payload = Hash(Symbol | String, String | Bool | Int32 | Int64 | Float32 | Float64 | Nil) 
    @payload : Payload 

    def initialize(@payload, @method : String = "sendMessage") 
    end 

    def to_json 
    @payload.merge({"method" => @method}).to_json 
    end 
end 

Response.new({ 
    "chat_id" => update.message.not_nil!.chat.id, 
    "text" => "Crystal is awesome but complicated", 
}) 

をしかし、私はinstance variable '@payload' of Response must be Hash(String | Symbol, Bool | Float32 | Float64 | Int32 | Int64 | String | Nil), not Hash(String, Int64 | String)コンパイラエラーを取得します。どうすればこれを克服できますか?クリスタルは一般ハッシュをサポートしていますか?型が重なっても変換できないのはなぜですか?

Responseは断片の一部ですので、どのハッシュが引数として渡されるのかわかりませんが、Payloadで十分です。

+1

おそらくハッシュを誤って使用していると思います。これは、ハッシュが一般的な "データバッグ"として使われているRubyとは非常に異なっています。 Crystalでは、ここでハッシュを使用する代わりに、カスタムクラスまたはレコードタイプを作成したいと考えています。違いは、ハッシュの場合、キーと値の型との間には関係がないため、この目的のために使用することは非常に難しいことです。クラスを作成する場合、各プロパティは独自の型を持ち、より簡単に使用できます。 CrystalでRubyをプログラミングしようとしないでください。 – RX14

+0

@ RX14参照してください。私はRubyで以前よりも多くのコードを書く必要があります。しかし、それは私に良いパフォーマンスと少ないエラーを与える:) –

+0

はい、それはより多くのコードですが、しばしばあなたのバグが実行時にコンパイラでキャッチされているとして長い時間で短い時間です。数ヶ月後にコードに戻ったら、何が起こっているのかを簡単に伝えることができます。 – RX14

答えて

3

あなたのペイロードハッシュはタイプHash(String, Int32 | String)は次のとおりです。

typeof({ 
    "chat_id" => update.message.not_nil!.chat.id, 
    "text" => "Crystal is awesome but complicated", 
}) # => Hash(String, Int32 | String) 

しかし、コンストラクタはHash(Symbol | String, String | Bool | Int32 | Int64 | Float32 | Float64 | Nil)を期待しています。 これらは異なるタイプであり、魔法のようにキャストすることはできません。ペイロードのタイプが正しいことを確認する必要があります。これを行うには

一つの方法は、明示的にリテラルハッシュの種類を宣言することです:

Payload{ 
    "chat_id" => update.message.not_nil!.chat.id, 
    "text" => "Crystal is awesome but complicated", 
} 

もちろんこれは素晴らしいではありませんが、あなたのユースケースに応じて、それは十分かもしれません。

任意のタイプのハッシュを受信できる汎用インターフェイスを使用する場合は、Payloadタイプにキャストする必要があります。私は、一致するものとは異なるタイプのバリエーションの数を変換するために、Crinjaにこのアプローチを使用しています、実際の例について

def self.new(hash, method : String = "sendMessage") 
    payload = Payload.new 
    hash.each do |key, value| 
    payload[key] = value 
    end 
    new(payload, method) 
end 

:これは、そのタイプの新しいハッシュにデータをコピーすることを意味します。

+0

ハッシュリテラルを短縮するには、 'Payload {" chat_id "=> update.message.not_nil!.chat.id、" text "=>"クリスタルは素晴らしいですが複雑です "}'を使用することができます。 – RX14

+0

私はいつもこのハッシュリテラルの構文を忘れています...:D元の答えを更新しました。 –

+0

このような詳細な回答ありがとうございます@JohannesMüller –

関連する問題