Ruby | 文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分け

More than 3 years have passed since last update.


Ruby | 文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分け


概要

文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分けについて。


Object#to_s と Object#to_str に関する Matz さんの発言


Matz さんの発言

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/18648

to_sは(どのオブジェクトにもデフォルトで定義されている)文字列

化のフォーマットを変えるために再定義します。

to_strはそのクラス/オブジェクトが文字列として振る舞うことが
できるようにするために定義します。


Object#to_s


るりまのドキュメント

http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_s.html

明示的な変換。

Kernel#print や文字列の変数展開でも使われている to_s。

オブジェクトの文字列表現を返却する。

オブジェクトの文字列化が目的。


Object#to_str


るりまのドキュメント

http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_str.html

暗黙的な変換。

文字列の + 演算子利用時に呼び出されている to_str。


Matz さんの発言

Stringと類似のメソッド集合を持たないオブジェクトはto_strを定義するべ

きではないように思います(実害がない限り)。

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/23332

ダックタイピングが目的。

つまり、String のように振る舞う


to_str の実装例

Rails の ActiveView の Template で to_str を実装していました


ActiveView::Template::Text / HTML / Resolver

https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/text.rb

https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/html.rb

https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/resolver.rb


to_s , to_str の動作確認用サンプルコード

class Person

attr_reader :name, :age

def initialize(name, age)
@name, @age = name, age
end

def to_str
@name
end
end

class NotStringPerson
attr_reader :name, :age

def initialize(name, age)
@name, @age = name, age
end

def to_s
@name
end
end

tanaka = Person.new("tanaka", 34)
suzuki = NotStringPerson.new("suzuki", 44)
puts "■ to_s, to_str を直接呼び出し"
puts "tanaka.to_s = " + tanaka.to_s
puts "tanaka.to_str = " + tanaka.to_str
puts "suzuki.to_s = " + suzuki.to_s
begin
puts "suzuki.to_str = " + suzuki.to_str
rescue => e
puts e.message
end

# + 演算子利用時に暗黙的に to_str を利用した変換が行われる
puts "■ + 演算子利用時の to_str 呼び出し確認"
puts "tanaka name = " + tanaka
begin
puts "suzuki name = " + suzuki
rescue => e
puts e.message
end

# 変数展開時にも暗黙的に to_s を利用した変換が行われる
puts "■ 変数展開"
puts "tanaka name = #{tanaka}"
puts "suzuki name = #{suzuki}"

class StringUser
def self.use_string(text)
fail 'error!' unless text.respond_to? :to_str
text = text.to_str
puts text.upcase
end
end

puts "■ StringUser クラスから呼び出し"
StringUser.use_string("hoge")
StringUser.use_string(tanaka)
begin
StringUser.use_string(suzuki)
rescue => e
puts e.message
end


  • 出力

■ to_s, to_str を直接呼び出し

tanaka.to_s = #<Person:0x2bcd370>
tanaka.to_str = tanaka
suzuki.to_s = suzuki
undefined method `to_str' for #<NotStringPerson:0x2bcd328 @name="suzuki", @age=44>
■ + 演算子利用時の to_str 呼び出し確認
tanaka name = tanaka
no implicit conversion of NotStringPerson into String
■ 変数展開
tanaka name = #<Person:0x2bcd370>
suzuki name = suzuki
■ StringUser クラスから呼び出し
HOGE
TANAKA
error!


参照