28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby で s が nil か String か分らぬとき s.to_s と s || '' はどっちがいい?

Last updated at Posted at 2015-02-05

s に String か nil が入っているとき,nil を空文字列扱いにして処理したい場合があるよね。

その場合,s.to_ss || '' とどっちがいいんだろう?というお話。

nil.to_s は空文字列を返すのでどっちでも同じじゃん,と思いがちだけど,微妙な違いがある。文字コードが違うのだ。

p ''.to_s.encoding #=> #<Encoding:UTF-8>
p nil.to_s.encoding #=> #<Encoding:US-ASCII>

たいがい,この違いは気にしなくてもいい。UTF-8 が「ASCII 互換エンコーディング」なので,US-ASCII の文字列との間で比較や結合もできるし,index で互いに検索したり,splitscan の引数に使っても問題ない。

ただ,もし UTF-8 でしか動かない処理に投入するのであれば,s.to_s は使ってはいけないことになる。

実際,そういう目に遭った。UTF-8 と CP932 の両方に対応した文字列処理メソッドで,encoding の値で場合分けしていたところ,想定外だった US-ASCII の空文字が来ちゃって死んだ。

2021-08-25 追記:Ruby 2.7 で nil.to_s は frozen

Ruby 2.7.0 で,nil.to_s にわずかな非互換性が導入された(ことを Ruby 3.0 時代になってから思い出した)。
このバージョンからは nil.to_s凍結された空文字列を返すようになったのだ。しかも,何回実行しても常に同じオブジェクトが返される。

# Ruby 2.6 の場合

empty_strings = Array.new(3){ nil.to_s }

p empty_strings.first.frozen? # => false
p empty_strings.map{ |s| s.object_id }.uniq.count # => 3
# Ruby 2.7 以降の場合

empty_strings = Array.new(3){ nil.to_s }

p empty_strings.first.frozen? # => true
p empty_strings.map{ |s| s.object_id }.uniq.count # => 1

一方,文字列リテラル "" は,マジックコメントで frozen-string-literaltrue にしていない限り,凍結されていない空文字列を返す。そして評価されるたびに新たな String オブジェクトが作られる。

よって,s.to_ss || "" のどちらがよいかは,snil のときに凍結された空文字列が欲しいのかどうかも検討することになる。

28
25
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?