配列に追加
開始したスレッドを配列に追加し、全員の終了をjoinで待つというプログラムの練習です。
threads = [] 10.times { |n| threads << Thread.start { 1000.times { print "#{n}," } } } threads.each { |t| t.join }
文字列リテラル
Rubyでは、'...'と%q|...|は変数の展開をしません。"..."と%Q|...|は展開します。
name = "rubyco" print 'Hello, #{name}' ".\n" # => Hello, #{name}. (展開しない) print "Hello, #{name}.\n" # => Hello, rubyco. (展開する) print %q|#{name} says, "Hello."| "\n" # => #{name} says, "Hello." (展開しない) print %Q|#{name} says, "Hello."| "\n" # => rubyco says, "Hello." (展開する)
実行結果です。
Hello, #{name}. Hello, rubyco. #{name} says, "Hello." rubyco says, "Hello."
scan
p "abcdababcd".scan(/b.*d/) p "abcdababcd".scan(/b.*?d/)
["bcdababcd"] ["bcd", "babcd"]
|と||の違い
Rubyでは、演算子|は両方を評価しますが、||はショートカットショートサーキットになります。これはJavaも同じです(booleanの論理演算子|と||)。
class Rubyco def self.test if true | check print "1\n" end if true || check print "2\n" end end def self.check print "Check\n" true end end Rubyco.test
実行結果。
Check 1 2
疑問:どうしてri "TrueClass#|"は調べられるのに ri "TrueClass#||"は調べられないのでしょうね。それは||のほうはLispで言うところの特殊形式だからでしょうか。メソッドの引数のように評価しないからでしょうか。riで||を調べるにはどうしたら良いのでしょう。→制御構造
>ri "TrueClass#|" ------------------------------------------------------------ TrueClass#| true | obj => true ------------------------------------------------------------------------ Or---Returns +true+. As _anObject_ is an argument to a method call, it is always evaluated; there is no short-circuit evaluation in this case. true | puts("or") true || puts("logical or") _produces:_ or >ri "TrueClass#||" Nothing known about TrueClass#||
追記:
コメントでs/ショートカット/ショートサーキット/を教えていただきました。感謝!
flattenとflatten!
Rubyでは、多くの破壊的メソッドに!が付いています。ただし、すべての破壊的メソッドに!がついているわけではありません。
flattenとflatten!では、!のついた方が破壊的メソッドです。a.flattenの戻り値はフラットにした新しい配列ですが、a.flatten!の戻り値はaです。aそのものがフラットになったのです。
a = ["A", ["B", "C"], ["D", "E"]] p a b = a.flatten p b if a == b print "flatten: same\n" else print "flatten: not same\n" end b = a.flatten! p a if a == b print "flatten!: same\n" else print "flatten!: not same\n" end
実行結果です。
["A", ["B", "C"], ["D", "E"]] ["A", "B", "C", "D", "E"] flatten: not same ["A", "B", "C", "D", "E"] flatten!: same
attr_readerでアクセサ作り
Rubyでは、attr_readerを使うと属性へのアクセサ(ゲッタ)を作れます。以下のプログラムでは@attr1のgetterはありますが、@attr2のgetterはありません。ですからo.attr2でエラーになります。
class Rubyco attr_reader :attr1 def initialize(attr1, attr2) @attr1 = attr1 @attr2 = attr2 end end o = Rubyco.new(123, 456) p o.attr1 p o.attr2
実行結果の抜粋です。
123 undefined method `attr2' for #<Rubyco:0x2946f58 @attr2=456, @attr1=123> (NoMethodError)
joinでスレッド待ち
RubyのThread.startはスレッドオブジェクトを返すので、それとjoinすれば起動したスレッドを待つことになります。
Thread.start { 10.times { p Thread.current } }.join Thread.start { 10.times { p Thread.current } }.join
実行結果。
#<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x29470c0 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run> #<Thread:0x2946f40 run>
Stringも拡張できる
Rubyは、組み込みのStringクラスでも拡張できます。debug_printメソッドとtwiceメソッドを追加してみました。
class String def debug_print print "Debug: #{self}\n" return self end def twice return self + self end end p "Hello".debug_print p "Hello".twice.debug_print
実行結果。
Debug: Hello "Hello" Debug: HelloHello "HelloHello"