Ruby:为什么传递给 send() 的输入被包裹在哈希中?
Ruby: why are inputs passed to send() being wrapped in a Hash?
我正在使用 Ruby 中的 send() 方法来调用我定义的方法。该方法采用 OpenStruct
.
这是一个片段,展示了我如何使用 send
:
调用我的方法
my_open_struct = OpenStruct.new(foo: "foo")
result = @my_object.send(
:my_method_that_takes_an_openstruct,
name_of_openstruct_param: my_open_struct)
问题是在 my_method_that_takes_an_openstruct
中,OpenStruct
参数被包裹在 Hash
中,导致日志输出如下:
Just before calling send #<OpenStruct foo="foo">
Inside my_method_that_takes_an_openstruct: {:name_of_openstruct_param=>#<OpenStruct foo="foo">}
为什么会发生这种情况,如何防止这种环绕行为?
我假设 my_method
看起来像这样
class Foo
def my_method(arg)
puts "#{arg}"
end
end
如果您来自 Python 背景,您可能认为我们可以将 my_method
称为 foo.my_method(1)
或 foo.my_method(arg: 1)
。但这不是它在 Ruby 中的工作方式。在 Ruby 中,参数是 命名的或位置的。为了命名一个参数,我们在它后面放一个冒号。
class Foo
def my_method(arg:)
puts "#{arg}"
end
end
现在我们可以做 Foo.new.my_method(arg: 1)
或 Foo.new.send(:my_method, arg: 1)
,但是 不正确 做 Foo.new.my_method(1)
。
您获得哈希的原因是兼容性技巧。在旧版本的 Ruby 中,在我们命名参数之前,惯例是在末尾采用单个散列参数
def foo(a, b, opts)
...
end
然后下面的两个调用是等价的(前者是后者的语法糖)
foo(1, 2, foo: "bar", bar: "baz")
foo(1, 2, {foo: "bar", bar: "baz"})
基本上,如果参数列表中出现任何类似名称的参数,它们将被转换为单个散列并作为最终参数传递给函数。
此行为是 Ruby 3.0 中的 deprecated as of Ruby 2.7 and removed。现在正确的约定是采用显式命名参数,Ruby 的最新版本支持双 splat **
运算符,用于将散列 转换为 命名参数,类似于具有相同名称的 Python 运算符。
我正在使用 Ruby 中的 send() 方法来调用我定义的方法。该方法采用 OpenStruct
.
这是一个片段,展示了我如何使用 send
:
my_open_struct = OpenStruct.new(foo: "foo")
result = @my_object.send(
:my_method_that_takes_an_openstruct,
name_of_openstruct_param: my_open_struct)
问题是在 my_method_that_takes_an_openstruct
中,OpenStruct
参数被包裹在 Hash
中,导致日志输出如下:
Just before calling send #<OpenStruct foo="foo">
Inside my_method_that_takes_an_openstruct: {:name_of_openstruct_param=>#<OpenStruct foo="foo">}
为什么会发生这种情况,如何防止这种环绕行为?
我假设 my_method
看起来像这样
class Foo
def my_method(arg)
puts "#{arg}"
end
end
如果您来自 Python 背景,您可能认为我们可以将 my_method
称为 foo.my_method(1)
或 foo.my_method(arg: 1)
。但这不是它在 Ruby 中的工作方式。在 Ruby 中,参数是 命名的或位置的。为了命名一个参数,我们在它后面放一个冒号。
class Foo
def my_method(arg:)
puts "#{arg}"
end
end
现在我们可以做 Foo.new.my_method(arg: 1)
或 Foo.new.send(:my_method, arg: 1)
,但是 不正确 做 Foo.new.my_method(1)
。
您获得哈希的原因是兼容性技巧。在旧版本的 Ruby 中,在我们命名参数之前,惯例是在末尾采用单个散列参数
def foo(a, b, opts)
...
end
然后下面的两个调用是等价的(前者是后者的语法糖)
foo(1, 2, foo: "bar", bar: "baz")
foo(1, 2, {foo: "bar", bar: "baz"})
基本上,如果参数列表中出现任何类似名称的参数,它们将被转换为单个散列并作为最终参数传递给函数。
此行为是 Ruby 3.0 中的 deprecated as of Ruby 2.7 and removed。现在正确的约定是采用显式命名参数,Ruby 的最新版本支持双 splat **
运算符,用于将散列 转换为 命名参数,类似于具有相同名称的 Python 运算符。