gpt4 book ai didi

ruby - 为什么 `*` 的子类上的 `String` 返回接收者的类?

转载 作者:数据小太阳 更新时间:2023-10-29 08:08:17 25 4
gpt4 key购买 nike

如果我创建了 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

为什么 * 的行为不同于 +%

最佳答案

不令人满意的答案是……因为它是那样实现的。

这是 the implementationString#+Rubinius :

def +(other)
other = StringValue(other)
Rubinius::Type.compatible_encoding self, other
String.new(self) << other
end

如您所见,它显式构造了一个String,这就是为什么它总是返回一个String

这是 the implementationString#%在 Rubinius 中:

def %(args)
*args = args
ret = Rubinius::Sprinter.get(self).call(*args)

ret.taint if tainted?
return ret
end

它使用 Rubinius::Sprinter用于格式化 String,它总是返回一个 String

最后,这是 the implementationString#*在 Rubinius 中:

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

这里有趣的部分是它不是通过调用 String.pattern 而是通过调用 self.class.pattern 来尝试找到一个类方法,所以它实际上会改为调用 MyString::patternString::pattern 实际上实现为 primitive ,我不是很熟悉,但我相信有趣的是 this :

String* s = state->new_object_dirty<String>(as<Class>(self));
// ^^^^^^^^^^^^^^^

JRuby ,我认为魔术是here :

RubyString result = new RubyString(context.runtime, getMetaClass(), bytes);
// ^^^^^^^^^^^^^^

有趣的是,在 Topaz ,该类是 String,而不是 MyString:

topaz -e 'class MyStr < String; end; p MyStr.new.*(2).class'
# => String

已实现here (我认为):

  def mul(self, space, storage, times):
return space.newstr_fromchars(self.unerase(storage) * times)

事实证明,ISO Ruby Language Specification关于 String#* 有这样的说法:

Create a direct instance S of the class String the content of which is C repeated n times.

请注意它是如何说“直接实例”的,即不是 String 子类的实例,而是 String 本身的实例。因此,乍一看,YARV、JRuby 和 Rubinius 似乎违反了此处的规范。但是,此规范适用于 String#*,而不适用于 MyString#*,因此问题是:如果方法由子类继承,此规范是否也适用?维护规范中的不变性是子类的责任,还是即使 String 被子类化,String#* 也有责任维护不变性但是 String#* 没有被覆盖?

关于ruby - 为什么 `*` 的子类上的 `String` 返回接收者的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28443844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com