Ruby:从 Class 方法中更改实例
Ruby: Change Instances from Within Class Method
我有两个要交换的 class 实例。两个实例都是数组。我想使用 class 方法交换它们。我如何 change/access class 方法 self.collide
中的实例?
class MagicBus < Array
attr_writer :seating
def self.collide(bus1, bus2)
stored_arr1 = bus1
stored_arr2 = bus2
bus1 = stored_arr2
bus2 = stored_arr1
return bus1, bus2
end
end
def test_two_magic_buses_collide_and_swap_their_passengers
bus1 = MagicBus.new(["Mark","Dale","Peter"])
bus1_object_id = bus1.object_id
bus2 = MagicBus.new(["James","Patrick","Bardoe"])
bus2_object_id = bus2.object_id
MagicBus.collide(bus1, bus2)
assert_equal ["James","Patrick","Bardoe"], bus1
assert_equal bus1_object_id, bus1.object_id
assert_equal ["Mark","Dale","Peter"], bus2
assert_equal bus2_object_id, bus2.object_id
end
我试过下面的代码,没有用,但应该说明我正在尝试做什么。
def self.collide(bus1, bus2)
stored_arr1 = bus1
stored_arr2 = bus2
bus1 = stored_arr2
bus2 = stored_arr1
self.bus1 = bus2
self.bus2 = bus1
end
测试结果是...
....E
Error:
TestMagicBus#test_two_magic_buses_collide_and_swap_their_passengers:
NoMethodError: undefined method `bus1=' for MagicBus:Class
magic_bus.rb:56:in `collide'
magic_bus.rb:126:in `test_two_magic_buses_collide_and_swap_their_passengers'
您尝试执行的操作在 Ruby 中是不可能的,因为 Ruby 没有“按引用传递”参数,但始终按指针传递。这意味着当您在方法中对参数进行赋值时,这不会更改外部变量的值:
a = "Hello"
def make_message(param)
param = "Hello, my Friend"
end
make_message(a)
a => Still has the value "Hello"
接下来,在您的代码示例中您引用了 self.bus1
,但您尚未声明这样的成员字段。这就是您收到错误的原因。
要实现您的目标,您需要使用数组 class 的方法,这会更改提供的实例:
a = [1,2,3]
b = [4,5,6]
def swap_array_content(x, y)
temp = y.dup # Need to make a temporary copy here
y.replace(x)
x.replace(temp)
end
swap_array_content(a, b)
p a
p b
这 在 Ruby 中是 可能的。当您将一个对象传递给一个方法时,该方法接收到一个指向该对象本身的指针。这意味着在对象上调用的任何可变方法都会影响它。
您的代码不起作用,因为您只是在创建新的局部变量,而不是修改传递的对象
def self.collide(bus1, bus2)
stored_arr1 = bus1 # assign bus1 address to stored_arr1
stored_arr2 = bus2 # assign bus2 address to stored_arr2
bus1 = stored_arr2 # create new local variable named bus1, assign it bus2's original address
bus2 = stored_arr1 # create new local variable named bus2, assign it bus1's original address
return bus1, bus2 # return bus2's original address followed by bus1's
end
您必须使用变异方法来修改传递的对象
def self.collide bus1, bus2
tmp = bus1.dup # create a copy of bus1
bus1.replace bus2 # replace bus1 in-place
bus2.replace tmp # replace bus2 in-place
# no need to return, bus1 and bus2 have been modified. the caller can use the ones passed in
end
考虑到 class 个实例完全由它们的实例变量的值来表征(前提是尚未在特定实例上定义单例方法),我们可以简单地交换这些值。
class C
attr_reader :seating, :colour
def initialize(seating, colour)
@seating = seating
@colour = colour
end
def self.collide(bus1, bus2)
var2 = bus2.instance_variables.map { |v| bus2.instance_variable_get(v) }
bus2.instance_variables.each do |v|
bus2.instance_variable_set(v, bus1.instance_variable_get(v))
bus1.instance_variable_set(v, var2.shift)
end
end
end
bus1 = C.new(46, 'blue')
bus2 = C.new(32, 'red')
[bus1.seating, bus1.colour]
#=> [46, "blue"]
[bus2.seating, bus2.colour]
#=> [32, "red"]
C.collide(bus1, bus2)
[bus1.seating, bus1.colour]
#=>[32, "red"]
[bus2.seating, bus2.colour]
#=> [46, "blue"]
我有两个要交换的 class 实例。两个实例都是数组。我想使用 class 方法交换它们。我如何 change/access class 方法 self.collide
中的实例?
class MagicBus < Array
attr_writer :seating
def self.collide(bus1, bus2)
stored_arr1 = bus1
stored_arr2 = bus2
bus1 = stored_arr2
bus2 = stored_arr1
return bus1, bus2
end
end
def test_two_magic_buses_collide_and_swap_their_passengers
bus1 = MagicBus.new(["Mark","Dale","Peter"])
bus1_object_id = bus1.object_id
bus2 = MagicBus.new(["James","Patrick","Bardoe"])
bus2_object_id = bus2.object_id
MagicBus.collide(bus1, bus2)
assert_equal ["James","Patrick","Bardoe"], bus1
assert_equal bus1_object_id, bus1.object_id
assert_equal ["Mark","Dale","Peter"], bus2
assert_equal bus2_object_id, bus2.object_id
end
我试过下面的代码,没有用,但应该说明我正在尝试做什么。
def self.collide(bus1, bus2)
stored_arr1 = bus1
stored_arr2 = bus2
bus1 = stored_arr2
bus2 = stored_arr1
self.bus1 = bus2
self.bus2 = bus1
end
测试结果是...
....E
Error:
TestMagicBus#test_two_magic_buses_collide_and_swap_their_passengers:
NoMethodError: undefined method `bus1=' for MagicBus:Class
magic_bus.rb:56:in `collide'
magic_bus.rb:126:in `test_two_magic_buses_collide_and_swap_their_passengers'
您尝试执行的操作在 Ruby 中是不可能的,因为 Ruby 没有“按引用传递”参数,但始终按指针传递。这意味着当您在方法中对参数进行赋值时,这不会更改外部变量的值:
a = "Hello"
def make_message(param)
param = "Hello, my Friend"
end
make_message(a)
a => Still has the value "Hello"
接下来,在您的代码示例中您引用了 self.bus1
,但您尚未声明这样的成员字段。这就是您收到错误的原因。
要实现您的目标,您需要使用数组 class 的方法,这会更改提供的实例:
a = [1,2,3]
b = [4,5,6]
def swap_array_content(x, y)
temp = y.dup # Need to make a temporary copy here
y.replace(x)
x.replace(temp)
end
swap_array_content(a, b)
p a
p b
这 在 Ruby 中是 可能的。当您将一个对象传递给一个方法时,该方法接收到一个指向该对象本身的指针。这意味着在对象上调用的任何可变方法都会影响它。
您的代码不起作用,因为您只是在创建新的局部变量,而不是修改传递的对象
def self.collide(bus1, bus2)
stored_arr1 = bus1 # assign bus1 address to stored_arr1
stored_arr2 = bus2 # assign bus2 address to stored_arr2
bus1 = stored_arr2 # create new local variable named bus1, assign it bus2's original address
bus2 = stored_arr1 # create new local variable named bus2, assign it bus1's original address
return bus1, bus2 # return bus2's original address followed by bus1's
end
您必须使用变异方法来修改传递的对象
def self.collide bus1, bus2
tmp = bus1.dup # create a copy of bus1
bus1.replace bus2 # replace bus1 in-place
bus2.replace tmp # replace bus2 in-place
# no need to return, bus1 and bus2 have been modified. the caller can use the ones passed in
end
考虑到 class 个实例完全由它们的实例变量的值来表征(前提是尚未在特定实例上定义单例方法),我们可以简单地交换这些值。
class C
attr_reader :seating, :colour
def initialize(seating, colour)
@seating = seating
@colour = colour
end
def self.collide(bus1, bus2)
var2 = bus2.instance_variables.map { |v| bus2.instance_variable_get(v) }
bus2.instance_variables.each do |v|
bus2.instance_variable_set(v, bus1.instance_variable_get(v))
bus1.instance_variable_set(v, var2.shift)
end
end
end
bus1 = C.new(46, 'blue')
bus2 = C.new(32, 'red')
[bus1.seating, bus1.colour]
#=> [46, "blue"]
[bus2.seating, bus2.colour]
#=> [32, "red"]
C.collide(bus1, bus2)
[bus1.seating, bus1.colour]
#=>[32, "red"]
[bus2.seating, bus2.colour]
#=> [46, "blue"]