如果我创建String
的子类,*
将返回该类的实例。
class MyString < String
end
MyString.new("foo").*(2).class #=> MyString
这与+
和%
等其他类似操作不同,后者会返回String
个实例。
MyString.new("foo").+("bar").class #=> String
MyString.new("%{foo}").%(foo: "bar").class #=> String
为什么*
的行为与+
和%
不同?
答案 0 :(得分:1)
不满意的答案是......因为它是以这种方式实现的。
以下为the implementation中String#+
的Rubinius:
def +(other)
other = StringValue(other)
Rubinius::Type.compatible_encoding self, other
String.new(self) << other
end
正如您所看到的,它明确地构建了一个String
,这就是它总是返回String
的原因。
以下是Rubinius中the implementation的String#%
:
def %(args)
*args = args
ret = Rubinius::Sprinter.get(self).call(*args)
ret.taint if tainted?
return ret
end
它使用Rubinius::Sprinter
格式化String
,String
始终返回def *(num)
num = Rubinius::Type.coerce_to(num, Integer, :to_int) unless num.kind_of? Integer
if num.kind_of? Bignum
raise RangeError, "bignum too big to convert into `long' (#{num})"
end
if num < 0
raise ArgumentError, "unable to multiple negative times (#{num})"
end
str = self.class.pattern num * @num_bytes, self
return str
end
。
最后,这是Rubinius的the implementation String#*
:
String.pattern
这里有趣的部分是,它试图通过调用self.class.pattern
而不是通过调用MyString::pattern
来查找类方法,因此它实际上会调用String::pattern
。 String* s = state->new_object_dirty<String>(as<Class>(self));
// ^^^^^^^^^^^^^^^
实际上是以primitive实现的,我不是很熟悉,但我相信有趣的是this:
RubyString result = new RubyString(context.runtime, getMetaClass(), bytes);
// ^^^^^^^^^^^^^^
String
有趣的是,在Topaz中,该课程为MyString
,而不是topaz -e 'class MyStr < String; end; p MyStr.new.*(2).class'
# => String
:
def mul(self, space, storage, times):
return space.newstr_fromchars(self.unerase(storage) * times)
已实施here(我认为):
String#*
事实证明,ISO Ruby Language Specification可以说String
:
创建类
String
的直接实例 S ,其内容 C 重复 n 次。
注意它是如何表示“直接实例”,即不是String
的子类的实例,而是String#*
本身的实例。所以,乍一看,似乎YARV,JRuby和Rubinius违反了规范。但是,此规范适用于MyString#*
,而不适用于String#*
,因此问题是:如果方法由子类继承,此规范是否也适用?子类是否负责维护规范中的不变量,或者String
是否有责任维护不变量,即使String#*
是子类但{{1}}不是覆盖?