时间:2018-01-26 23:35:58

标签: crystal-lang

我们说我在聊天中代表了一条消息的Message课程。

class Message
    JSON.mapping({
        message_id: {type: Int32},
        text:       {type: String, nilable: true},
        photo:      {type: Photo, nilable: true},
        sticker:    {type: Sticker, nilable: true},
    })

    MESSAGE_TYPES = %w( text photo sticker )

    {% for type in MESSAGE_TYPES %}
        def {{ type.id }}?
        ! {{ type.id }}.nil?
        end
    {% end %}
end

每封邮件都可以是文字,照片或贴纸。但只有其中一个。例如,如果消息是文本,则photosticker属性为零,但text不为零。如果邮件是贴纸,则只有sticker不是零。等等。真实类有更直接的类型和推断类型。

收到此消息后,我想以特定类型的特定方式处理它。类似的东西:

case message
when .text?
    p message.text
when .photo?
    p message.photo.file_id
when .sticker?
    p message.sticker.file_id
end

当然,它不会起作用,因为在每个when子句中,相应的属性是可以使用的undefined method 'file_id' for Nil

有没有办法在每种情况下限制变量类型,确保message.sticker?然后message.sticker不是nil且file_id存在?

也许我在解决问题方面完全错误,并且有更好,更清晰的方法对此进行编码?

2 个答案:

答案 0 :(得分:2)

struct mystruct {
  var a = "11215"
  var b = "21212"
  var c = "39932"
}

func loopthrough {
    for (key, value) in mystruct {
        print("key: \(key), value: \(value)") // Type mystruct.Type does not conform to protocol 'Sequence'
    }
}

答案 1 :(得分:2)

您可以将所有有效负载对象放在一个带有联合类型的实例变量中,如Oleh Prypin建议的那样。 另一个选项是,如果要保留当前数据布局,可以让方法返回相应的类型或nil并将其值赋给变量:

if text = message.text?
  p text
if photo = message.photo?
  p photo.file_id
if sticker = message.sticker?
  p sticker.file_id
end