如果无法在编译时确定数据类型,如何检测 Crystal 中的数据类型?
How to detect data types in Crystal if they cannot be determined at compile-time?
我正在用 crystal-lang for the Ethereum RLP 标准编写递归编码器。
我要做的是获取任何要编码的传入数据 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
我正在用 crystal-lang for the Ethereum RLP 标准编写递归编码器。
我要做的是获取任何要编码的传入数据 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