如果我有一个表示某种字符串类型的自定义Ruby类,如
class MyString
end
为了使以下用例成为可能,我应该实现哪些功能:
MyString
时传递Ruby字符串MyString
MyString
值进行比较(无论我使用s == t
还是t == s
都无关紧要。)我已经看到了各种有趣的函数,例如to_s
,cmp
,==
和eq
,但是当我们调用每个函数时,我都不清楚。
我的具体用例是我正在使用C API编写一个Ruby扩展,它公开了获取(并返回)自定义字符串类型(QString
的值的函数),我的扩展也注册了。但是,我想让这些自定义字符串尽可能直观。不幸的是,我不能只从我的C代码中返回Ruby字符串,因为它应该可以在字符串上调用Qt方法。
答案 0 :(得分:6)
至少有三种方法:
class MyString < String; ...; end
#to_s
#to_str
同时执行#2和#3将使对象非常像真正的String,即使它不是子类。
#to_s
是一个显式转换器,意味着它必须出现在Ruby代码中才能工作。
#to_str
是一个隐式转换器,意味着Ruby解释器会在需要String时尝试调用它,但是会给出其他内容。
更新
以下是您可以使用to_str
获得一些乐趣的示例:
begin
open 1, 'r'
rescue TypeError => e
p e
end
class Fixnum
def to_str; to_s; end
end
open 1, 'r'
运行时,第一次打开失败并显示TypeError
,但第二次打开则会查找1
。
#<TypeError: can't convert Fixnum into String>
fun.rb:9:in `initialize': No such file or directory - 1 (Errno::ENOENT)
from fun.rb:9:in `open'
答案 1 :(得分:1)
尽管将String子类赋予它一个新的initialize
方法来导入这些QString类型的字符串很诱人,但你可能只想添加一个有助于转换的String扩展,这样你就不会不得不重新实现String本身的版本。
例如,使用两种方法你几乎可以完成这项工作:
class String
def self.from_qstring(qstring)
new(...)
end
def to_qstring
# ...
end
end
在开始比较它们之前,为String提供多种存储类型不会成为问题,但鉴于Ruby的String非常强大,编写类似的工作很困难。
答案 2 :(得分:0)
继承Ruby中其他人构建的类通常不是一个好主意,因为太多事情可能会出错。 (例如,您可能会在不知情的情况下覆盖内部方法。)
1)定义Mystring.to_s以获得从Mystring到String的自动转换。
2)不确定你的意思。如果你想要一个返回Mystring的String方法,你将不得不修补String:
Class String
def to_mystring
return Mystring.new(self)
end
end
3)得到t == s(假设s是String的实例,t是Mystring的一个实例)定义&lt; =&gt;。为了获得s == t,你将不得不再次使用补丁字符串。