Programming Ruby(読書ノート)-9章(式)
15826 ワード
Rubyのどの文にも対応する戻り値があります.
ifとcaseブロックは、最後の文の実行結果を返します.
9.1操作式
+-*/はオペレータであり、実際にはメソッドです.a*b+c:aオブジェクトでメソッド*、パラメータはb、返された結果オブジェクトでメソッド+、パラメータはcを呼び出します.
----インスタンスメソッドを再定義することができる----
この有用な方法は、カスタムクラスにサポートオペレータを追加する方法です.
--------some_obj[1,2,3]は呼び出しsome_を表すobjの[]メソッドで、パラメータは1 2 3---
--------[]=方法----------
9.2様々な表現
上の式はすべて表示される操作式で、ifとcaseのようなそんなに明らかではない式を説明します.
Command Expansion拡張コマンド
`%または%x{}を含む場合、rubyはオペレーティングシステムコマンドとして実行します.対応する戻りは、コマンドの標準出力であり、改行が含まれる場合があります.
$?コマンドの実行結果ステータスを取得するグローバル変数です
逆引用符の再定義
Assignment賦課
lvalue=rvalue=>右参照の値を左参照に割り当て、式の結果としてrvalueを返します.
Parallel Assignment(並列付与)
Rubyでは複数の値を同時に複数の変数に割り当てることができます
並列に値を割り当てるプロセス:Rubyは右側に複数の要素があることを発見し、まずそれらを計算し、1つの配列に配置し(すでに配列であればしない)、右側を見て、右側に1つの要素(分割子が分かれていない)がある場合は、数のグループ全体を割り当てます.そうしないと、1つの値を割り当て、超えた部分は捨てられます.足りなければ価値がない.
Splats(*を接頭辞として使用)and Assignment
右側にspatがある場合は配列が割り当てられます
もしsplatが最後の位置でなかったら?まず単一のマッチング会を、残りをspatに分け、なくなったら空の配列に分けます.
メソッドのパラメータと同様に、余分なパラメータを無視することができます.
Nested Assignment(ネスト割り当て)
左側の変数には、()がネストされた値であることを示す場合、右側の対応する位置の値を抽出して割り当て、左側が配列である場合、右側が1つの値である場合、左側にネストされた最初の値のみが割り当てられます.
Other Forms of Assignment
9.4 Conditional Execution(条件実行)
Boolean Expressions
Rubyでは、値がnilまたは表示される設定値がfalse(constant false)でない限りtrueとなります."cat", 99, 0, and :a_song are all considered true.
And, Or, and Not
注意:これらのオペレータはtrueまたはfalseだけを返します.実際の値かもしれません.
&&and:1番目がfalseの場合、1番目を返します.そうでない場合、2番目の値を返します.
|or:1番目がtrueの場合、1番目を返します.そうでない場合、2番目の値を返します.
----優先順位---
andはorの優先度と同じですが、&&の比は高いです.
||=は、変数にデフォルト値を設定するためによく使用されます.すなわち、変数が指定された値に割り当てられていない場合です.
! not:取り戻しです.!(1 and 2)
defined?
パラメータが定義されていない場合はnilを返し、定義されている場合はパラメータの説明を返します.
パラメータがyieldで、現在のコンテキストにコードブロックがある場合は、「yield」列を返します.
Comparing Objects(比較操作)
boolean操作の補足としてRubyは=,==,<=>,=~,eql?,equal?
<=>以外(Object.instance_methodsを使って発見してもこの方法はあるのでしょうか?)ベースクラスObjectには既に存在するが、Arrayの==など、対応する意味を表すために上書きされることが多く、2つの配列の長さが一致し、各要素が等しいことを表すために上書きされる.
==と=~の相返し操作は!=と!~.再呼び出し!=または!の場合、Rubyはこの2つのメソッド名を先に操作し、見つからない場合は==と=~を呼び出し、結果を返します.
オペレータの意味:
==等しいか
==右が左にあるかどうか
<=>生成-1,0,+1,より小さい,等しい,より大きい
=~正規表現の一致
eql?受信者とパラメータには、同じタイプと等しい値があります.1==1.0はtrueを返しますが、1.eql?(1.0)falseを返す
equal?受信者はパラメータと同じオブジェクトIDを持つ
------区間はboolean式で使用されます---
exp1..exp2 :false...->exp1(=true)->true...->exp2(true)->false
if and unless Expressions(もしそうでなければ)
なければ
if and unless Modif(if unlessの改良版)
9.5 case Expressions(case)
when keyword
この文の実際の原理は===に依存し,Rubyはtargetを各whenの文と比較した.クラス==メソッドが実装されている限り、このシーンで使用できます.
9.6 Loops
whileとutilの改良スタイルがbeginに使われている場合...endブロックの場合、条件がtrueであるかどうかにかかわらず、少なくとも1回実行されます.以下のようにします.
Iterators
クラスは、eachメソッドを提供することによって、クライアントによって反復されることを提供することができる.
loopサイクル
for...in
反復+ブロックコードで置き換えることができます.
クラスにeach(大文字と小文字が敏感)メソッドが定義されている限り、for...inを使用してこのオブジェクトを反復することができます.
break,redo and next
break:ジャンプ
redo:最初からもう一度来ますが、条件文が実行されないか、iteratorでnext要素が取得されないことに注意してください.
next:iteratorの場合、loopの最後にスキップします.つまり、今回は次のコードを実行しません.
この3つのキーワードは、コードブロックにも使用できます.
9.7 Variable Scope,Loops,and Blocks(ループまたはブロック内の変数範囲)
また、ブロックコードのパラメータセクションに、内部で使用される変数名を定義して表示することもできます.これにより、重複しても外部と衝突しません.
a = b = c = 0 # => 0
[ 3, 1, 7, 0 ].sort.reverse # => [7, 3, 1, 0]
ifとcaseブロックは、最後の文の実行結果を返します.
song_type = if song.mp3_type == MP3::Jazz
if song.written < Date.new(1935, 1, 1)
Song::TradJazz
else
Song::Jazz
end
else
Song::Other
end
#case
rating = case votes_cast
when 0...10 then Rating::SkipThisOne
when 10...50 then Rating::CouldDoBetter
else Rating::Rave
end
9.1操作式
+-*/はオペレータであり、実際にはメソッドです.a*b+c:aオブジェクトでメソッド*、パラメータはb、返された結果オブジェクトでメソッド+、パラメータはcを呼び出します.
a, b, c = 1, 2, 3
a * b + c # => 5
#a.*
(a.*(b)).+(c) # => 5
----インスタンスメソッドを再定義することができる----
# Fixnum +
class Fixnum
alias old_plus + # +
def +(other)
old_plus(other).succ
end
end
1 + 2 # => 4
a = 3
a += 4 # => 8
a + a + a # => 26
この有用な方法は、カスタムクラスにサポートオペレータを追加する方法です.
class ScoreKeeper
def initialize
@total_score = @count = 0
end
def <<(score)
@total_score += score
@count += 1
self #
end
def average
fail "No scores" if @count.zero? # count 0
Float(@total_score) / @count
end
end
scores = ScoreKeeper.new
scores << 10 << 20 << 40
puts "Average = #{scores.average}"
produces:
Average = 23.333333333333332
--------some_obj[1,2,3]は呼び出しsome_を表すobjの[]メソッドで、パラメータは1 2 3---
class SomeClass
def [](p1, p2, p3)
...
end
end
--------[]=方法----------
# : n ,
class SomeClass
def []=(*params)
value = params.pop #
puts "Indexed with #{params.join(', ')}" #
puts "value = #{value.inspect}"
end
end
9.2様々な表現
上の式はすべて表示される操作式で、ifとcaseのようなそんなに明らかではない式を説明します.
Command Expansion拡張コマンド
`%または%x{}を含む場合、rubyはオペレーティングシステムコマンドとして実行します.対応する戻りは、コマンドの標準出力であり、改行が含まれる場合があります.
`date` # => "Mon May 27 12:30:56 CDT 2013
"
`ls`.split[34] # => "newfile"
%x{echo "hello there"} # => "hello there
"
for i in 0..3
status = `dbmanager status id=#{i}`
# ...
end
$?コマンドの実行結果ステータスを取得するグローバル変数です
逆引用符の再定義
alias old_backquote `
def `(cmd)
result = old_backquote(cmd)
if $? != 0 # $?
puts "*** Command #{cmd} failed: status = #{$?.exitstatus}"
end
result
end
print `ls -l /etc/passwd`
print `ls -l /etc/wibble`
produces:
-rw-r--r-- 1 root wheel 5086 Jul 20 2011 /etc/passwd
ls: /etc/wibble: No such file or directory
*** Command ls -l /etc/wibble failed: status = 1
Assignment賦課
lvalue=rvalue=>右参照の値を左参照に割り当て、式の結果としてrvalueを返します.
a = b = 1 + 2 + 3
a # => 6
b # => 6
a = (b = 1 + 2) + 3
a # => 6
b # => 3
File.open(name = gets.chomp)
# , 2
class Test
def val=(val)
@val = val
return 99
end
end
t = Test.new
result = (t.val= 2)
puts result
prduces:
2
Parallel Assignment(並列付与)
Rubyでは複数の値を同時に複数の変数に割り当てることができます
a,b = 1,2
a,b = b,a #=>[2,1] 2,1,
並列に値を割り当てるプロセス:Rubyは右側に複数の要素があることを発見し、まずそれらを計算し、1つの配列に配置し(すでに配列であればしない)、右側を見て、右側に1つの要素(分割子が分かれていない)がある場合は、数のグループ全体を割り当てます.そうしないと、1つの値を割り当て、超えた部分は捨てられます.足りなければ価値がない.
a = 1, 2, 3, 4 #=> a=[1, 2, 3, 4]
b = [1, 2, 3, 4] #=> b=[1, 2, 3, 4]
a, b = 1, 2, 3, 4 #=> a=1, b=2
c, = 1, 2, 3, 4 #=> c=1
Splats(*を接頭辞として使用)and Assignment
# , ,
a, b, c, d, e = *(1..2), 3, *[4, 5] #=> a=1, b=2, c=3, d=4, e=5
右側にspatがある場合は配列が割り当てられます
a, *b = 1, 2, 3 #=> a=1, b=[2, 3]
a, *b = 1 #=> a=1, b=[]
もしsplatが最後の位置でなかったら?まず単一のマッチング会を、残りをspatに分け、なくなったら空の配列に分けます.
*a, b = 1, 2, 3, 4 #=> a=[1, 2, 3], b=4
c, *d, e = 1, 2, 3, 4 #=> c=1, d=[2, 3], e=4
f, *g, h, i, j = 1, 2, 3, 4 #=> f=1, g=[], h=2, i=3, j=4
メソッドのパラメータと同様に、余分なパラメータを無視することができます.
first, *, last = 1,2,3,4,5,6 #=># first=1, last=6
Nested Assignment(ネスト割り当て)
左側の変数には、()がネストされた値であることを示す場合、右側の対応する位置の値を抽出して割り当て、左側が配列である場合、右側が1つの値である場合、左側にネストされた最初の値のみが割り当てられます.
a, (b, c), d = 1,2,3,4 #=> a=1, b=2, c=nil, d=3
a, (b, c), d = [1,2,3,4] #=> a=1, b=2, c=nil, d=3
a, (b, c), d = 1,[2,3],4 #=> a=1, b=2, c=3, d=4
a, (b, c), d = 1,[2,3,4],5 #=> a=1, b=2, c=3, d=5
a, (b,*c), d = 1,[2,3,4],5 #=> a=1, b=2, c=[3, 4], d=5
Other Forms of Assignment
# + , a +=1,
class Bowdlerize
def initialize(string)
@value = string.gsub(/[aeiou]/, '*')
end
def +(other)
Bowdlerize.new(self.to_s + other.to_s)
end
def to_s
@value
end
end
a = Bowdlerize.new("damn ") # => d*mn
a += "shame" # => d*mn sh*m*
# a = a.+ ("shame")
#a + , a to_s , a.to_s
9.4 Conditional Execution(条件実行)
Boolean Expressions
Rubyでは、値がnilまたは表示される設定値がfalse(constant false)でない限りtrueとなります."cat", 99, 0, and :a_song are all considered true.
And, Or, and Not
注意:これらのオペレータはtrueまたはfalseだけを返します.実際の値かもしれません.
&&and:1番目がfalseの場合、1番目を返します.そうでない場合、2番目の値を返します.
nil && 99 # => nil
false && 99 # => false
"cat" && 99 # => 99
|or:1番目がtrueの場合、1番目を返します.そうでない場合、2番目の値を返します.
----優先順位---
andはorの優先度と同じですが、&&の比は高いです.
||=は、変数にデフォルト値を設定するためによく使用されます.すなわち、変数が指定された値に割り当てられていない場合です.
var ||="default value"
#var = var || "default value
! not:取り戻しです.!(1 and 2)
defined?
パラメータが定義されていない場合はnilを返し、定義されている場合はパラメータの説明を返します.
パラメータがyieldで、現在のコンテキストにコードブロックがある場合は、「yield」列を返します.
defined? 1 # => "expression"
defined? dummy # => nil
defined? printf # => "method"
defined? String # => "constant"
defined? $_ # => "global-variable"
defined? Math::PI # => "constant"
defined? a = 1 # => "assignment"
defined? 42.abs # => "method"
defined? nil # => "nil"
Comparing Objects(比較操作)
boolean操作の補足としてRubyは=,==,<=>,=~,eql?,equal?
<=>以外(Object.instance_methodsを使って発見してもこの方法はあるのでしょうか?)ベースクラスObjectには既に存在するが、Arrayの==など、対応する意味を表すために上書きされることが多く、2つの配列の長さが一致し、各要素が等しいことを表すために上書きされる.
==と=~の相返し操作は!=と!~.再呼び出し!=または!の場合、Rubyはこの2つのメソッド名を先に操作し、見つからない場合は==と=~を呼び出し、結果を返します.
オペレータの意味:
==等しいか
==右が左にあるかどうか
<=>生成-1,0,+1,より小さい,等しい,より大きい
=~正規表現の一致
eql?受信者とパラメータには、同じタイプと等しい値があります.1==1.0はtrueを返しますが、1.eql?(1.0)falseを返す
equal?受信者はパラメータと同じオブジェクトIDを持つ
------区間はboolean式で使用されます---
exp1..exp2 :false...->exp1(=true)->true...->exp2(true)->false
if and unless Expressions(もしそうでなければ)
if artist == "Gillespie" then
handle = "Dizzy"
elsif artist == "Parker" then
handle = "Bird"
else
handle = "unknown"
end
# , then。 ,
if artist == "Gillespie" then handle = "Dizzy"
elsif artist == "Parker" then handle = "Bird"
else handle = "unknown"
end
なければ
unless duration > 180
listen_intently
end
# duration 180,
if and unless Modif(if unlessの改良版)
mon, day, year = $1, $2, $3 if date =~ /(\d\d)-(\d\d)-(\d\d)/
puts "a = #{a}" if $DEBUG
print total unless total.zero?
# , ,
/^\s*$/
/^$/
File.foreach("/etc/passwd") do |line|
next if line =~ /^#/ # Skip comments
parse(line) unless line =~ /^$/ # Don't parse empty lines
end
9.5 case Expressions(case)
if..elsif
case
when song.name="Misty"
puts "Not again!"
when song.duration > 120
puts "Too long!"
when Time.now.hour > 21
puts "it's too late!"
else
song.play
end
,case 。
case command
when "debug"
dump_debug_info
dump_symbols
when /p\s+(\w+)/
dump_variable($1)
when "quit", "exit"
exit
else
print "Illegal command: #{command}"
end
# , when ... then ..., 。
case target when keyword
この文の実際の原理は===に依存し,Rubyはtargetを各whenの文と比較した.クラス==メソッドが実装されている限り、このシーンで使用できます.
case line
when /title=(.*)/
puts "Title is #$1"
when /track=(.*)/
puts "Track is #$1"
end
Rubyのclassは、パラメータが受信者のインスタンスまたはサブタイプインスタンスであるかどうかを判断するための==メソッドを定義するClassクラスのインスタンスです.case shape
when Square, Rectangle
# ...
when Circle
# ...
when Triangle
# ...
else
# ...
end
9.6 Loops
while condition
#...
end
util , ,
util play_list.duration > 60
play_list.add(song_list.pop)
end
a = 1
a *=2 while a < 100
a #=>128
a -= 10 until a< 100
a #=>98
Rubyの区間(Range)は、トリガ(スイッチ)として使用され、あることが発生したときにtrueとなり、その後、あることが発生したときに再びfalseとなる.a = (11..20).collect { |i| (i%4==0)..(i%3) ? i : nil}
a ->[nil, 12,nil,nil,nil,16,17,18,nil,20]
a = (11..20).collect { |i| (i%4==0)...(i%3) ? i:nil}
a ->[nil,12,13,14,15,16,17,18,nil,20]
#.. exp2, ... , 。
# third , fifth 。
file = File.open("ordinal")
while line = file.gets
puts(line) if line =~ /third/ .. line =~/fifth/
end
produces:
third
fourth
fifth
# boolean
File.foreach("ordinal") do |line|
if (($. == 1) || line =~ /eig/) .. (($. == 3) || line =~ /nin/)
print line
end
end
produces:
first
second
third
eighth
ninth
ここにRubyの特殊な変数を挿入します$!
$@
$_ gets
$. (line number)
$&
$~
$n n ( $~[n] )
$=
$/
$\
$0 Ruby
$*
$$ ID
$?
$: default search path (array of paths)
whileとutilの改良スタイルがbeginに使われている場合...endブロックの場合、条件がtrueであるかどうかにかかわらず、少なくとも1回実行されます.以下のようにします.
print "Hello
" while false
begin
print "Goodbye
"
end while false
produces:
Goodbye
Iterators
# times
3.times do
print "ho"
end
# upto
0.upto(9) do |x|
print x, " "
end
produces:
0 1 2 3 4 5 6 7 8 9
# step, 3
0.step(12, 3) {|x| print x, " " }
produces:
0 3 6 9 12
# each
[ 1, 1, 2, 3, 5 ].each {|val| print val, " " }
produces:
1 1 2 3
クラスは、eachメソッドを提供することによって、クライアントによって反復されることを提供することができる.
File.open("ordinal").grep(/d$/) do |line|
puts line
end
produces:
second
third
loopサイクル
loop do
# block...
end
for...in
反復+ブロックコードで置き換えることができます.
#for...in
for i in ['fee', 'fi', 'fo', 'fum']
print i, " "
end
for i in 1..3
print i, " "
end
for i in File.open("ordinal").find_all {|line| line =~ /d$/}
print i.chomp, " "
end
produces:
fee fi fo fum 1 2 3 second third
クラスにeach(大文字と小文字が敏感)メソッドが定義されている限り、for...inを使用してこのオブジェクトを反復することができます.
class Periods
def each
yield "Classical"
yield "Jazz"
yield "Rock"
end
end
periods = Periods.new
for genre in periods
print genre, " "
end
produces:
Classical Jazz Rock
break,redo and next
break:ジャンプ
redo:最初からもう一度来ますが、条件文が実行されないか、iteratorでnext要素が取得されないことに注意してください.
next:iteratorの場合、loopの最後にスキップします.つまり、今回は次のコードを実行しません.
#next break redo
while line = gets
next if line =~ /^\s*#/ # skip comments
break if line =~ /^END/ # stop at end
# substitute stuff in backticks and try again
redo if line.gsub!(/`(.*?)`/) { eval($1) }
# process line ...
end
この3つのキーワードは、コードブロックにも使用できます.
i=0
loop do
i += 1
next if i < 3
print i
break if i > 4
end
produces:
345
9.7 Variable Scope,Loops,and Blocks(ループまたはブロック内の変数範囲)
# , ,
x = "initial value"
y = "another value"
[1, 2, 3].each do |x|
y = x + 1
end
[x, y] #=>["initial value", 4]
# ,
a = "never used" if false #a
[99].each do |i|
a = i
end
a #=>99
Ruby 。
また、ブロックコードのパラメータセクションに、内部で使用される変数名を定義して表示することもできます.これにより、重複しても外部と衝突しません.
# ,
square = "yes"
total = 0
[ 1, 2, 3 ].each do |val; square|
square = val * val
total += square
end
puts "Total = #{total}, square = #{square}"
produces:
Total = 14, square = yes