`

Programming Ruby(读书笔记)-9章(表达式)

    博客分类:
  • Ruby
 
阅读更多

Ruby中任何语句都有一个相应的返回值。

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\n"
`ls`.split[34]         # => "newfile"
%x{echo "hello there"} # => "hello there\n"
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发现右边有多个元素,会先把它们计算出来,然后放置到一个数组中(如果已经是数组则不做),然后查看右则,如果右则只有一个元素(没有分割符分开),则将整个数组分配给它,否则,逐个赋值,超出的部分被抛弃。不够则无值。

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(嵌套赋值)

左边的变量可使用()包括表示是嵌套赋值,则提取右边对应位置的值赋给它们,如果左边是数组,右边就一个值,则只会给左边嵌套的第一个赋值。

 

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 :如果第一个为false,则返回第一个,否则返回第二个的值.

nil && 99    # => nil
false && 99 # => false
"cat" && 99 # => 99

|| or:如果第一个为true,则返回第一个,否则返回第二个的值

----优先级---

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的==,会覆盖以表示两个数组的长度一致,并且每个元素相等。

 

==与=~的相返操作是!=与!~。再调用!=或!~时,Ruby会先操作这两个方法名,如果没有找到,会调用==与=~,然后把结果取返。

 

操作符的语义:

==   是否值相等

=== 右边是否在左边中

<=>  产生-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 Modifiers(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,都至少会执行一次,如下:
print "Hello\n" while false
begin
  print "Goodbye\n"
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

 这三个关键字还可以用于代码块

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

 

 

 

 

 

 

分享到:
评论

相关推荐

    Programming Ruby(读书笔记)-3章

    《Programming Ruby》是一本关于Ruby编程语言的经典书籍,它的第三章深入探讨了Ruby的基本语法和核心概念。在这一章中,作者介绍了变量、常量、符号、数组、哈希等核心数据类型,以及控制流(条件语句和循环)和方法...

    Programming Ruby - The Pragmatic Programmer's Guide, 2nd Edition (2005) [annotated]

    《Programming Ruby - The Pragmatic Programmer's Guide》第二版(2005年注释版)是一本在IT行业中享有盛誉的经典书籍,专门针对Ruby编程语言进行了深入浅出的讲解。该书不仅覆盖了Ruby语言的基础知识,还探讨了其...

    Programming-Ruby-1.9源代码

    《Programming Ruby 1.9》是一本经典的Ruby编程语言教程,其源代码包含了大量实例和示例,旨在帮助读者深入理解Ruby的语法、特性以及编程实践。这些源代码是学习和探索Ruby语言的重要资源,涵盖了从基础语法到高级...

    Ruby学习资料(含参考手册和Programming Ruby)-中文.rar

    "ruby--.txt"可能是一个文本文件,其中包含了Ruby的代码示例、笔记或者问题解答,通过阅读可以加深对Ruby语法和实践的理解。 "Ruby语言入门教程附实例"和"ruby-mht"文件很可能是包含实例的教程,实践是学习编程的...

    Programming-Ruby-1.9.pdf

    - **正则表达式**: Ruby内置了强大的正则表达式引擎,方便进行文本处理。 - **块和迭代器**: 块是Ruby中的匿名函数,常用于数组和集合的操作。 - **文件操作**: Ruby提供了丰富的文件和目录操作API。 - **命令行参数...

    Programming ruby.pdf

    《Programming Ruby》是一本关于Ruby编程语言的经典著作,由Dave Thomas、Andy Hunt和Chad Fowler合著。这本书自2004年初版以来,一直是学习Ruby的首选资源,被誉为“Pickaxe”书,因其封面的图标而得名。Ruby是一种...

    Programming Ruby (English Version) and Source Code

    《Programming Ruby》是著名的Ruby语言教程,英文版的书籍旨在为全球开发者提供深入理解Ruby编程语言的途径。这本书详尽地介绍了Ruby的语法、特性、类库以及编程实践,是学习和进阶Ruby编程的宝贵资源。源代码的提供...

    Programming Ruby.pdf

    《Programming Ruby》被誉为是学习Ruby语言的最佳指南,这本书在IT界享有极高的声誉,被亲切地称为“镐头书”,其价值与影响力无远弗届。本书不仅详细介绍了Ruby语言的核心概念、语法结构以及编程实践,还深入探讨了...

    Programming Ruby中文版第二版[高清扫描版][带书签]和Programming.Ruby-2nd[高清文字版][带书签].pdf

    《Programming Ruby》中文版第二版是一本专注于Ruby编程语言的经典教程。这本书的两个版本——高清扫描版和高清文字版,都是为了便于读者学习和查阅,其中都带有书签功能,帮助读者快速定位到相关内容。 Ruby是一种...

    Programming Ruby 1.9 (3rd edition)和源码

    通过阅读《Programming Ruby 1.9 (3rd edition)》并研究提供的源码,开发者可以深入掌握Ruby 1.9的核心概念、设计模式以及最佳实践,从而提高编程效率和代码质量。这本书是Ruby开发者的必备参考资料,无论是初学者...

    Programming_ruby-2nd.pdf

    9. 编程理念的启示:根据上述推荐和评价,可以理解到《Programming Ruby》不仅仅是关于语言的语法和结构,而且深入探讨了如何以Ruby的方式思考和解决问题。 10. 编程语言的比较:Mike Clark在推荐语中提到,一旦...

    Programming Ruby

    通过阅读《Programming Ruby》,读者不仅可以学习到Ruby的基本语法,还能深入了解其背后的哲学和设计思想,从而成为一名高效的Ruby开发者。书中的实例和练习将帮助你更好地掌握Ruby编程,提升解决问题的能力。

    swift-RegexSwift正则表达式工具

    在Swift编程语言中,正则表达式(Regex)是一种强大的文本处理工具,用于匹配、查找、替换和解析字符串。在iOS和macOS开发中,Swift提供了`NSRegularExpression`类来处理正则表达式,它是Foundation框架的一部分。`...

    Programming Collective Intelligence -- 2008 -- code.7z

    Segaran -- Programming Collective Intelligence -- 2008 -- code.7z

    ruby-1.9.3-

    The TIOBE index, which measures the growth of programming languages, ranks Ruby as #9 among programming languages worldwide. Much of the growth is attributed to the popularity of software written in ...

    Ruby-Functional-Programming, 来自 Conferencia Rails 2011.zip

    Ruby-Functional-Programming, 来自 Conferencia Rails 2011 通过 Arnau Sanchez实现的ruby 函數式程式設計簡介理論部分Ruby的函數式程式設計不要更新變數不要重用變量用阻止作為高階函數物件導向與函數式程式設計萬...

    ruby-2.0.0-p0.tar

    3. ** Fiber和Concurrent Programming**:Ruby 2.0引入了Fiber,这是一种轻量级线程,用于实现协程。这为开发者提供了更好的并发处理能力,尤其是在I/O密集型任务中。 4. **块参数**:Ruby 2.0允许块参数以`&`符号...

Global site tag (gtag.js) - Google Analytics