【问题标题】:How do I write a method to edit an array/hash using parentheses instead of square brackets?如何编写使用括号而不是方括号来编辑数组/哈希的方法?
【发布时间】:2014-01-28 23:41:00
【问题描述】:

我正在尝试用 Ruby 编写内部 DSL,但在实现特定语法时遇到了麻烦。具体来说,如果我在一个类中有一个数组(或哈希),我想用括号访问和编辑它。例如:

class MyData
  attr_accessor :things
  def initialize
    @things = ['right', 'right', 'wrong']
  end
end

test = MyData.new

# This obviously won't work, but it's the syntax that I want.
test.things(2) = 'right'

我知道我可以通过以下方式读取具有这种语法的元素:

class MyData
  def things(index)
    @things[index]
  end
end

test = MyData.new
test.things(2) # => 'wrong' 

但实际上更改元素完全是另一回事,因为 Ruby 只是不知道如何处理该赋值运算符。

我想要这种奇怪的语法的原因是因为我希望我可以使用这种语言轻松地将一些 Fortran 名称列表文件转换为友好的 Ruby 环境,而 Fortran 不幸地用括号索引数组。

我担心这只是我努力使 Ruby 违背其核心语法的情况之一,我需要实际编写一个解析器。有什么想法吗?

【问题讨论】:

  • 那不能,也不应该起作用。这是一个语法错误。此外,对于有经验的程序员来说,它看起来是完全错误的。这不是 应该 起作用的语法。您可以在 C++ 中生成类似 in 的内容,您可以在其中定义自定义赋值运算符并返回对包装器对象的引用,但即便如此,您不应该这样做。
  • @meagar,我知道并完全同意这是糟糕的 ruby​​ 语法,但正如我所说,这是针对 DSL 的(我绝对不希望这会在常规的旧 ruby​​ 代码中引起混淆,但在我想使用它的上下文中它会非常有用甚至自然)。不幸的是,这种简化的解释使它看起来完全站不住脚。我只是想知道是否有人知道一个肮脏的黑客可以使我在这个项目中感兴趣。感谢您的意见!
  • 正如我所说,它不能。这是一个语法错误。 Ruby 无法运行此代码。再多的猴子补丁或元编程都无法做到这一点。
  • 这不是“糟糕的 Ruby 语法”。它是“不是 Ruby 语法”。时期。你不能在 Ruby 中编写不是 Ruby 的代码。

标签: ruby metaprogramming


【解决方案1】:

语法不是有效的 Ruby,所以你不能在 Ruby 中这样做。期间。

您有多种选择:

  1. 将您的语法更改为 有效的 Ruby:

    class MyData
      attr_reader :things
    
      private
    
      attr_writer :things
    
      def initialize
        self.things = %w[right right wrong]
      end
    end
    
    test = MyData.new
    
    test.things[2] = 'right'
    
    test.things
    # => ['right', 'right', 'right']
    
  2. 使用支持该语法的语言,例如 Scala:

    class MyData {
      var things = scala.collection.mutable.Seq("right", "right", "wrong")
    }
    
    val test = new MyData
    
    test.things(2) = "right"
    
    test.things
    // => scala.collection.mutable.Seq[String] = ArrayBuffer(right, right, right)
    
  3. 创建一个外部 DSL,即不是有效的 Ruby。

    事实上,看起来您已经一个定义良好的外部 DSL,特别是 Fortran 的一个子集。根据您是否可以控制这些名称列表文件,您甚至可以将语法进一步限制为可以通过一些 Regexps 和一些文本处理来轻松解析的内容。

【讨论】:

  • 感谢您提供选项。我现在选择选项 1,但在未来的某一天我可能会选择选项 2 或 3。
【解决方案2】:

调用运算符() 不能重载,所以你想做的技术上无法完成。一种选择是在将 DSL 交给 Ruby 之前预处理您的 DSL 以用括号替换括号。

查看this other answer 了解更多关于运算符重载的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    相关资源
    最近更新 更多