1

我正在尝试在对象上实现就地方法,但出现以下错误:

Can't change the value of self (SyntaxError)

当试图做

self = map(&block)

在以下对象上

class Node
  include Enumerable

  # binary tree representation
  attr_accessor :value, :left, :right
  def initialize(value=nil, left=nil, right=nil)
    @value, @left, @right = value, left, right
  end

  def map(&block)
    res = Array.new
    res << yield(value) if value
    res << left.map(&block) if left 
    res << right.map(&block) if right
    res.flatten
  end

  def map!(&block)
    self = self.map(&block)
  end

  def to_a
    map { |a| a }
  end
end

我也尝试过使用 Enumerable 的一些破坏性方法无济于事

map(&block).collect!

我的方法有什么问题,您将如何实现这样的功能?

更新

为了澄清这个想法是在二叉树上实现映射,上面的映射方法成功地做到了,我的问题是将该方法转换为就地版本。

irb(main):001:0> require './node.rb'
=> true
irb(main):002:0> root = @root = Node.new(1, Node.new(2, Node.new(3), Node.new(4)),Node.new(5, Node.new(6), Node.new(7)))
=> #<Node:0x78803f58 @value=1, @left=#<Node:0x78abc090 @value=2, @left=#<Node:0x78abc0f0 @value=3, @left=nil, @right=nil>, @right=#<Node:0x78abc0c0 @value=4, @left=nil, @right=nil>>, @right=#<Node:0x78803f88 @value=5, @left=#<Node:0x78abc060 @value=6, @left=nil, @right=nil>, @right=#<Node:0x78abc030 @value=7, @left=nil, @right=nil>>>
irb(main):003:0> root.map { |a| a * 3 }
=> [3, 6, 9, 12, 15, 18, 21]
irb(main):004:0> root
=> #<Node:0x778fb828 @value=1, @left=#<Node:0x778fb9c0 @value=2, @left=#<Node:0x778fba68 @value=3, @left=nil, @right=nil>, @right=#<Node:0x778fb9f0 @value=4, @left=nil, @right=nil>>, @right=#<Node:0x778fb888 @value=5, @left=#<Node:0x778fb930 @value=6, @left=nil, @right=nil>, @right=#<Node:0x778fb8b8 @value=7, @left=nil, @right=nil>>>
irb(main):005:0> root.map! { |a| a * 3 }
=> [3, 6, 9, 12, 15, 18, 21]]
irb(main):006:0> root
=> [3, 6, 9, 12, 15, 18, 21]
4

4 回答 4

2

它通常是这样实现的:

class Node

  attr_accessor :value, :left, :right

  def initialize_copy(source)
    super
    @value = @value.dup
    @left = @left.dup
    @right = @right.dup
  end

  def map(&block)
    dup.map!(&block)
  end

  def map!(&block)
    @value.map!(&block) if @value
    @left.map!(&block) if @left
    @right.map!(&block) if @right
    self
  end

end
于 2013-03-15T16:30:35.117 回答
1

self is a keyword, and it is not a variable. That is why you cannot do assignment to it.

于 2013-03-15T20:39:52.327 回答
0

这样的事情呢?

class Foo
  attr_accessor :bar

  def initialize(bar)
    @bar = bar
  end

  def update!
    self.instance_variables.each do |i| 
      self.instance_variable_set(i, yield(self.instance_variable_get(i)))
    end
  end
end
于 2013-03-15T16:59:25.153 回答
0

Enumerable 模块根据您的领域特定方法为您提供了一堆each方法。这些方法都不是破坏性的。

相反,我会使用 Enumerable 定义您自己的方法:

class Node

  # define each and include, or do it by hand to customize:

  Enumerable.instance_methods(false).each do |method|
    define_method(method) do |*args|
      # apply method to each instance variable
    end
  end

  %w( map reject etc.. ).each do |method|
    define_method("#{method}!") do |*args|
      results = send(method)
      # modify instance vars based on results
    end
  end

end
于 2013-03-15T17:23:31.817 回答