我是一位经验丰富的 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
(或类似的东西),所以至少我们被警告发生在哪里