精化是对v2.0的实验性补充,然后在v2.1中进行了修改并永久化.它提供了一种通过提供"在本地扩展类的方法"来避免"猴子修补"的方法.
我试图申请Refinements到这个最近的问题,我将因此简化:
a = [[1, "a"],
[2, "b"],
[3, "c"],
[4, "d"]]
b = [[1, "AA"],
[2, "B"],
[3, "C"],
[5, "D"]]
Run Code Online (Sandbox Code Playgroud)
在位置的元素i中a的元素相匹配的偏移i的b,如果:
a[i].first == b[i].first
Run Code Online (Sandbox Code Playgroud)
和
a[i].last.downcase == b[i].last.downcase
Run Code Online (Sandbox Code Playgroud)
换句话说,字符串的匹配与大小写无关.
问题是确定a匹配相应元素的元素数量b.我们看到答案是两个,即抵消的元素1和2.
一种方法是使用Monkey-patch String#==:
class String
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 2
Run Code Online (Sandbox Code Playgroud)
或者改为使用Refinements:
module M
refine String do
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
end
'a' == 'A'
#=> false (as expected)
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 0 (as expected)
using M
'a' == 'A'
#=> true
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 2
Run Code Online (Sandbox Code Playgroud)
但是,我想这样使用Refinements:
using M
a.zip(b).count { |ae,be| ae == be }
#=> 0
Run Code Online (Sandbox Code Playgroud)
但是,如你所见,这给出了错误的答案.那是因为我正在调用Array#==并且细化不适用于Array.
我能做到这一点:
module N
refine Array do
def ==(other)
zip(other).all? do |ae,be|
case ae
when String
ae.downcase==be.downcase
else
ae==be
end
end
end
end
end
using N
a.zip(b).count { |ae,be| ae == be }
#=> 2
Run Code Online (Sandbox Code Playgroud)
但这不是我想要的.我想做这样的事情:
module N
refine Array do
using M
end
end
using N
a.zip(b).count { |ae,be| ae == be }
#=> 0
Run Code Online (Sandbox Code Playgroud)
但显然这不起作用.
我的问题:有没有办法改进String使用Array,然后改进Array我的方法使用?
哇,这玩起来真的很有趣!感谢您提出这个问题!我找到了一个有效的方法!
module M
refine String do
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
refine Array do
def ==(other)
zip(other).all? {|x, y| x == y}
end
end
end
a = [[1, "a"],
[2, "b"],
[3, "c"],
[4, "d"]]
b = [[1, "AA"],
[2, "B"],
[3, "C"],
[5, "D"]]
using M
a.zip(b).count { |ae,be| ae == be } # 2
Run Code Online (Sandbox Code Playgroud)
如果不重新定义==,Array细化将不适用。有趣的是,如果您在两个单独的模块中执行此操作,它也不起作用;这是行不通的,例如:
module M
refine String do
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
end
using M
module N
refine Array do
def ==(other)
zip(other).all? {|x, y| x == y}
end
end
end
a = [[1, "a"],
[2, "b"],
[3, "c"],
[4, "d"]]
b = [[1, "AA"],
[2, "B"],
[3, "C"],
[5, "D"]]
using N
a.zip(b).count { |ae,be| ae == be } # 0
Run Code Online (Sandbox Code Playgroud)
我对实现细节不够熟悉,无法refine完全确定为什么会出现这种行为。我的猜测是,细化块的内部被视为进入不同的顶级范围,类似于当前文件外部定义的细化仅适用于在require当前文件中解析它们定义的文件时。这也可以解释为什么嵌套细化不起作用;内部精炼一退出就超出了范围。这也可以解释为什么猴子补丁Array如下有效:
class Array
using M
def ==(other)
zip(other).all? {|x, y| x == y}
end
end
Run Code Online (Sandbox Code Playgroud)
这不会成为refine所产生的范围问题的牺牲品,因此refineonString仍在范围内。
| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |