我是一位经验丰富的 Obj-C/Java 程序员,并且正在研究 Ruby。显然,它是如此动态的事实很棒(重新开放课程很棒!)但是当我开始编写 Ruby 代码时,有一件事让我感到烦恼/担心。
我很想知道你们 Ruby-ers 做了什么(如果有的话)来明确地在自己的类中设置 iVar 的类型。据我所知,您可以为任何对象设置 iVar,而 ruby 不会抱怨。但是,如果您希望特定 iVar 属于某种类型,那么它可能会导致问题。例如:
class MyString
  def initialize(myString)
    @myString = myString
  end
  def uppercase_my_string
    @myString.upcase
  end
end
st1 = MyString.new("a string!")
st1.uppercase_my_string
st2 = MyString.new(["a string"])
st2.uppercase_my_string
这段代码会抛出一个NoMethodError,因为数组当然没有方法upcase。不幸的是,它并没有告诉我们真正出错的地方(上面的行,创建时str2)所以我们在调试时没有多大帮助(如果str2碰巧在一些不显眼的地方创建了几个模块)一个自然的步骤可能是添加一些检查initialize如下:
class MyString
  def initialize(myString)
    raise TypeError, "myString iVar is not a string!" unless myString.class == String
    @myString = myString
  end
end
...same code as before
太好了,现在如果我们不小心创建了一个新的 MyString,我们会被告知我们是多么愚蠢(更重要的是,当我们这样做而不是失败时,我们会被告知。打字有点痛苦,但没关系。我的下一个问题是我们决定attr_accessors在 iVar 上使用的时候。
class MyString
  attr_accessor :my_string
  def initialize(my_string)
    raise TypeError, "myString iVar is not a string!" unless my_string.class == String
    @my_string = my_string
  end
  def uppercase_my_string
    @my_string.upcase
  end
end
st1 = MyString.new("a string!")
st1.uppercase_my_string
st2 = MyString.new("good, it's a string")
st2.my_string = ["an array!"]
st2.uppercase_my_string
使用定义的 setter,我们可以偷偷摸摸地绕过错误检查initialize。这再次存在抛出异常的问题,uppercase_my_string而不是当我们意外设置@my_string为数组时。
最后,我们可以手动创建访问器并添加错误检查,但这是一个巨大的痛苦......有没有更快更简单的方法来做到这一点。还是我只是思想封闭,不够有活力?
谢谢!
旁白:我知道在 Obj-C 中你在运行时仍然有同样的问题,但通常你会发现编译器错误,说你正在将一个类型的对象分配给一个类型array的变量string(或类似的东西),所以至少我们被警告发生在哪里