有没有办法在Crystal中使用带有splat运算符的非元组对象?

时间:2018-03-07 22:50:03

标签: crystal-lang splat

是否有一些函数或语法结构可以使下一个例子有效?

使用Hash#values_at参数调用Array函数:

h = {"a" => 1, "b" => 2, "c" => 3}
ary = ["a", "b"]
h.values_at(*ary) # Error: argument to splat must be a tuple, not Array(String)

传递Hash初始化类或结构:

struct Point                                                                                                 
    def initialize(@x : Int32, @y : Int32)                                                                     
    end                                                                                                        
end
h = {"x" => 1, "y" => 2}
Point.new(**h) # Error: argument to double splat must be a named tuple, not Hash(String, Int32)

2 个答案:

答案 0 :(得分:5)

根据具体情况,第一个例子可能是不可能的。但是,如果元素的长度是固定的,您可以这样做:

.

https://carc.in/#/r/3oot请参阅Tuple.from

h = {"a" => 1, "b" => 2, "c" => 3} ary = ["a", "b"] p h.values_at(*{String, String}.from(ary)) 支持相同的方法:

NamedTuple

https://carc.in/#/r/3oov请参阅NamedTuple.from

这些只是确保类型和在运行时手动分解结构的一些糖,主要用于数据来自外部源,例如从JSON解析。

当然,我们首选在可能的情况下首先在struct Point def initialize(@x : Int32, @y : Int32) end end h = {"x" => 1, "y" => 2} p Point.new(**{x: Int32, y: Int32}.from(h)) Tuple之上创建并使用Array而不是NamedTuple

答案 1 :(得分:2)

Array和Hash是动态扩展的容器,元素的数量可以在运行时更改,当你尝试splat它时,数组可能是空的。

Tuple和NamedTuple由固定数量的元素组成,这些元素在编译时是已知的,因此它们可以用于splats。如果数据容器的格式没有改变,你可以改为使用Tuple和NamedTuple。

ary = {"a", "b"}
h.values_at(*ary)
相关问题