如何实现如下功能
a = [1,2,3,4,5]
b =a[0..2]
b[0] = 100
期望a[0] 也是100
Array 的 slice 函数和中括号语法有什么区别吗,
只要 a 和 b 是不同的对象,你这个需求就很难实现。想知道什么情况下需要实现这样的效果? Array#slice和Array#[]没区别,Array.instance_method(:[])==Array.instance_method(:slice) 返回 true。其实看文档就知道了
这需求有点奇怪,直接改 a,取的时候才去slice(0, 2)
岂不是更好?
a = [1,2,3,4,5]
b = a
b[0] = 100
b.slice(0, 2).each
现在的问题是切片返回的对象应该是原对象的视图,而不应该是元数据的拷贝。这里有些不一致你们不觉得吗。 a[3] =x 语义修改 a 的原素 而 a.slice(0) 的语义和 a[3] 不一样,slice 返回的是拷贝,而不是引用
@lilijreey 这个有点意思,你说的这种 slice 是 Golang 切片,Ruby 的数组没有这个效果。
不过,我们可以通过 Ruby 简单实现一个类似的效果。
class RefArray < Array
attr :ref, :range
def initialize(*args)
options = args.last.is_a?(Hash) ? args.pop : {}
@ref = options[:ref] || Array.new(*args)
@range = options[:range]
end
def [](index)
case index
when Integer
current_array[index]
when Range
new_range = Range.new(index.first + range_from,
index.last + range_from)
self.class.new(ref: @ref, range: new_range)
end
end
def []=(index, value)
if (index < current_array.size)
ref[range_from + index] = value
else
raise "index can't be larger than array length"
end
end
def inspect
current_array
end
def to_a
current_array
end
private
def current_array
range ? ref[range] : ref
end
def range_from
range ? range.first : 0
end
end
然后使用起来也十分顺滑:
a = RefArray.new([1, 2, 3, 4, 5])
b = a[0..2]
b[0] = 100
p b # [100, 2, 3]
p a # [100, 2, 3, 4, 5]
PS:为什么我要用ref
作为变量?因为 React 是真的香啊!哈哈哈!
RefArray 实例对象内部维护了一个 ref
和range
属性,记录原始的数组引用,以及你的切片范围。
当然你使用arr[x..y]
进行“切片”的时候,会生成一个包含ref
传递以及新的切片范围 range 的 RefArray 实例。
这样你每次切片,原始数组ref
都会传递下去,而变化的只是range
切片范围,所以当你进行赋值操作的时候,也就只是对原始数组进行更改。
而当你使用arr[x]
获取某个 index 的值的时候,获取的其实是根据当前切片范围和 index 映射在原始数组ref
上真实 index 对应的值。
其实就是一个手动维护的引用效果。