首页 > 解决方案 > 为什么相同类型的 NamedTuple 不兼容?

问题描述

为什么同类型的NamedTuple不兼容?

alias Data = NamedTuple(
  title: String?
)

data : Data = { title: nil }     # Explicitly specifying that 
                                 # it has ` : Data` type 

proc = ->(data : Data){ p data } 
proc.call data                   # And yet it says it's not 
                                 # of `Data` type

错误

Error: type must be NamedTuple(title: String | Nil), not NamedTuple(title: Nil)

标签: crystal-lang

解决方案


您的假设不正确:data : Data将局部变量的类型限制为Data(它是 的别名NamedTuple(title: String | Nil))。此类型限制不会影响右侧的值分配。文字值{type: nil}的类型为NamedTuple(title: Nil)。此类型与 的类型限制兼容Data,因此可以将其分配给变量。

这种隐式协变类型限制不适用于 proc 类型。我不确定这背后的原因。看来这应该可以工作。所以也许它只需要实施。

但是,您可以显式NamedTuple(Nil)转换为NamedTuple(String | Nil)

alias Data = NamedTuple(
  title: String?
)

data = { title: nil }.as(Data) # Cast named tuple to Data

proc = ->(data : Data){ p data } 
proc.call data

但是,将命名元组用作常规数据类型通常不是一个好主意。仅建议将它们用于非常特定的用例,例如命名参数。定义自定义结构(例如使用记录宏)是一个更好的主意,并为您提供更强大和灵活的数据类型。我会像这样实现你的例子:

record Data,
  title : String?

data = Data.new(title: nil)

proc = ->(data : Data){ p data } 
proc.call data

推荐阅读