我正在为以太坊 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
传递类型Int32
的32
将导致:
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