如果在编译时无法确定数据类型,如何检测 Crystal 中的数据类型?



我正在为以太坊 RLP 标准编写一个 crystal-lang 递归编码器。

我所要做的就是获取要编码的任何传入数据 blob 并确定其类型。现在,为了简单起见,我可以忽略无效类型。

RLP 编码的有效类型是二进制Bytes、字符串String或字符串列表Array(String)。到目前为止,一切顺利,我编写了三种允许三种数据类型的方法:

module Rlp
# rlp-encodes binary data
def self.encode(b : Bytes)
return "binary #{typeof(b)} #{b}"
end
# rlp-encodes lists data
def self.encode(l : Array(String))
return "listsy #{typeof(l)} #{l}"
end
# rlp-encodes string data
def self.encode(s : String)
return "strngy #{typeof(s)} #{s}"
end
end

但是,现在这里有一些深度,因为数组可以嵌套。因此,此编码器是递归的。给定一个Array(String)它会给它一些前缀,并用Rlp.encode(s : String)String进行编码。现在,拥有嵌套数组的逻辑是根据需要调用.encode来编码所有内容。但是,我无法弄清楚如何在编译时确定类型。

例如:

79 | Rlp.encode([["a", "b", "c"], ["cow", "dog", "cat"]])
^-----
Error: no overload matches 'Rlp.encode' with type Array(Array(String))

是的,因为我没有实现任何self.encode(l : Array(Array(String))),而且我无法知道这里的嵌套深度来潜在地实现所有可能的情况。

我试图实现不太严格的包装方法self.encode(data)不指定数据类型,但是,我基本上不能对data做任何事情,因为编译器根据我的用法暗示数据类型,即:

# rlp-encodes _any_ data
def self.encode(data)
if typeof(data) == Int32
return Bytes.new data
elsif typeof(data) == Char
return String.new data
end
end

传递类型Int3232将导致:

45 | return String.new data
Error: no overload matches 'String.new' with type Int32

即使不会使用Int32类型的数据调用此代码。我不确定如何在这里进行。在编译时不可知的情况下,是否对所使用的类型更聪明

?理想情况下,我会接受任何数据作为输入并自己处理不同的情况。

如果按如下方式声明 Array 的Rlp.encode,编译器将负责为不同类型的数组实例化该方法。

module Rlp
# rlp-encodes lists data
def self.encode(l : Array)
return "listsy #{typeof(l)} #{l}"
end
end

也许这在这里有点沉重,将所有值转换为.to_s

# rlp-encodes lists data
def self.encode(l : Array)
encode(l.flatten.compact.map(&.to_s))
end
def self.encode(l : Array(String))
return "listsy #{typeof(l)} #{l}"
end

最新更新