1

我想在 Ruby 中扩展变量的功能。原因是我正在研究类似于类型系统或值检查器的东西(这听起来有点疯狂,但整个想法很长,只是我想扩展默认变量的原因)。

我读过在 Ruby 中,一切都是对象。所以变量是对象。并且 Ruby 对于可以通过元编程更改的内容应该是相当自由的。

是否有某种与我可以扩展的局部变量相关的“类”?

我想为每个包含一个类型的字符串表示的变量关联一个字符串变量。此外,我想拦截变量分配并在每次将新值分配给变量时执行一个方法。这样我就可以根据类型检查新值是否正确(作为字符串存储在变量中)。

如果 Ruby 中的局部变量被定义为类的对象,我可以扩展该类或通过 ruby​​ mixin 修改它。

解决方法是为我的变量创建一个新类(而不是使用 Ruby 的本地变量的构建)。此类可以具有值属性、类型的属性(存储为字符串)以及获取和设置方法。这样我可以解决我的问题,但如果可能的话,我想扩展 ruby​​ 中的内置变量。

目前正在进行的工作

class Fixnum
        attr_accessor :tp
        @tp

        def mytype ( type )
                @tp = type
        end
        def typecheck
                #call typechecker
                puts "checked"
        end
end

测试代码:

a = 3
a.mytype("nat")
puts a.tp
a.typecheck

还有两个问题。 首先,我认为不可能向 Fixnum 添加新的构造函数。其次,我想拦截变量访问,即“b = a”调用a的方法'typecheck'。但这需要类似于面向方面编程的东西,我不确定这是否可以通过 Ruby 的元编程工具来解决。

4

3 回答 3

4

我在 Ruby 中读过,一切都是对象

这取决于您对“对象”和每个“事物”的定义。“对象”可以表示“可以被程序操作的实体”(从现在开始我将称之为对象),或者“作为对象系统成员的值”(从现在开始我将称之为Object)。

在Ruby 中,程序可以操作的所有东西(即每个对象)也是一个Object,即一个类的实例。这与 Java 不同,例如,原语可以由程序操作(即在这个词的意义上是对象),但不是Objects. 在 Ruby 中,不存在这种区别:每个对象都是一个对象Object,每个对象Object也是一个对象

但是,语言中有些东西不能被程序操作,也不是类的实例,即它们既不是object也不Object是 s。例如,这些是方法、变量、语法、参数列表、参数列表、关键字。

注意:你可以使用 Ruby 的反射 API 给你一个代表方法或参数列表的对象,但那个对象只是一个代理,它不是真实的东西。

所以,当我们说“一切都是对象”时,我们真正的意思是“每个对象都是一个Object”,即程序可以操作的一切都是对象系统的成员,或者换句话说,有在对象系统之外没有值(与 Java 中的原语不同)。我们并不是说该语言中存在的所有内容也可以在运行时由程序进行操作。

所以变量是对象

不,不幸的是,它们既不是object也不Object是 s。

这在 Ruby 语言规范中也有明确说明(重点由我添加):

6.2 变量

6.2.1 一般说明

变量由名称表示,并引用一个对象,称为变量的值。 变量本身不是对象

Matz 和 David Flanagan所著的 The Ruby Programming Language一书中,它在第 2 页上说:

每个值都是一个对象

请注意,它并没有说明所有内容,只说明了每个

另请参阅问题Is variable is object in ruby​​?

于 2012-08-27T18:20:23.987 回答
1

您可以做几件事。对于初学者,所有(或几乎所有)Ruby 类(包括诸如数字之类的“原语”)都支持 to_s 方法,该方法返回对象的字符串表示形式。对于数字,to_s 将只返回该数字的字符串表示形式(例如,“42”代表 42)。为其他类返回的字符串值会有所不同。好处是您可以通过 "monkey patching" 覆盖类的方法。这是一个非常人为的例子:

class Array
  def to_s
    return "An array of size #{self.size}."
  end
end

a = [1, 2, 3, 4]
puts a.to_s
# => "An array of size 4."

对于有关每次设置变量值时执行方法的其他问题,处理此问题的方法是始终通过其访问器方法与变量进行交互。这样,您可以在属性的 getter 和 setter 方法中实现自定义代码(或简单地从访问器内部调用另一个方法)。像这样:

class MyClass
  # Use the default getter for var.
  attr_reader :var      

  def initialize
    @var = 1
  end

  # Custom setter for var.
  def var= v
    @var = v
    puts "var changed to #{v}"
  end
end

mc = MyClass.new
mc.var = 9
# => "var chaged to 9"
于 2012-08-27T18:38:04.783 回答
0

你可以做这样的事情,但它只适用于全局:

$type_checked = {:$a => String, :$b => Array}
$type_checked.keys.each do |var|
  trace_var(var) do |obj|
    puts "hey, don't assign #{var} to a #{obj.class}" unless $type_checked[var] == obj.class
    #or raise an Error
  end
end

$a = 1
$a = "a"
$b = 1

#output:
#hey, don't assign $a to a Fixnum
#hey, don't assign $b to a Fixnum

但这显然违背了语言的本质。

于 2012-08-27T18:53:53.750 回答