多年前就很想学习一下RUBY,但是一直拖延症爆发,一件简单的事情居然拖了几年,新的一年,下定决心,决定首先花一星期时间把RUBY学习一下.

DAY 1 基本语法入门

1.1 安装

安装其实没什么可说的,基本参考https://www.ruby-lang.org/en/downloads/安装即可,我个人使用的是Cygwin,基本上在setup的时候勾选了ruby,打开Cygwin直接敲irb就好了. 
如果irb可以成功执行,那么这个安装就成功了.

1.2 快速入门

先从随便敲几句ruby语句开始快速入门:

1.2.1 解释执行

irb(main):001:0> puts 'hello,world' hello,world
=> nil
  • 输入后立刻得到反馈,说明ruby是可以解释执行的,而不需要编译成字节码.

1.2.2 更自由的变量

irb(main):002:0> language = 'RUBY'
=> "RUBY" irb(main):004:0* puts "hello,#{language}"
hello,RUBY
=> nil irb(main):005:0>  puts 'hello,#{language}'
hello,#{language} => nil

上面这段尝试可以发现:

  • ruby中不需要提前声明变量,变量可以直接被初始化和赋值(这样意味着变量的类型可以随着赋值的不同而随时改变)
  • 所有的ruby语句都有返回值
  • #{}可以求得变量的值(占位符并不局限于变量。任意放置在#{}中的合法Ruby代码都将被求值,并被替换为求值结果插入到原位置)
  • 目前可以看到有两种格式的字符串,一种是单引号包括的,这种单引号是不加改动的解释;另外一种是双引号包括的,会引发字符串替换.

1.2.3 万物皆对象

irb(main):008:0> 4
=> 4 irb(main):009:0> 4.class
=> Fixnum irb(main):010:0> 4.methods
=> [:to_s, :inspect, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, ...]

上面这段可以说明更多的问题:

  • 可以看到在ruby中万物皆对象,即使是一个数字
  • .methods可以打印出这个对象支持的所有方法数组
  • Ruby用[]表示数组
irb(main):012:0> -4.abs
=> 4 irb(main):014:0> 4.equal?4
=> true irb(main):015:0> -4.abs.equal?4
=> true irb(main):016:0> -4.equal?4
=> false irb(main):020:0> 4.instance_of?Fixnum
=> true irb(main):025:0> 4.!=4.class
=> true irb(main):027:0> (4.!=4).class
=> FalseClass
  • Ruby中使用带参数方法不需要括号,直接在方法后面
  • RUBY中存在优先级,括号可以影响优先级

1.2.4 字符串操作

irb(main):001:0> 'size'.length => 4 irb(main):004:0> 'size'.include?'si' => true irb(main):005:0> "Ruby is a beautiful language".start_with? "Ruby" => true irb(main):006:0> "I can't work with any other language but Ruby".end_with? 'Ruby' => true irb(main):007:0> 'size'.index'i' => 1 irb(main):008:0> 'size'.upcase => "SIZE" irb(main):009:0> 'SIZE'.downcase => "size" irb(main):010:0> "ThiS iS A vErY ComPlEx SenTeNcE".swapcase => "tHIs Is a VeRy cOMpLeX sENtEnCe" irb(main):011:0>  "I can't work with any other language but Ruby".split(' ') => ["I", "can't", "work", "with", "any", "other", "language", "but", "Ruby"]
irb(main):013:0> "I can't work with any other language but Ruby.I am happy.".sub('I','We') => "We can't work with any other language but Ruby.I am happy." irb(main):014:0> "I can't work with any other language but Ruby.I am happy.".gsub('I','We') => "We can't work with any other language but Ruby.We am happy." irb(main):015:0> 'RubyMonk'.gsub(/[aeiou]/,'1') => "R1byM1nk" irb(main):017:0> 'RubyMonk Is Pretty Brilliant'.gsub(/[A-Z]/,'0') => "0uby0onk 0s 0retty 0rilliant"

上面这些语句基本列出了主要的字符串操作函数,大多数语句的含义基本都是不言而喻的。有以下少数几点需要注意:

  • 依照Ruby惯例,如果某个方法返回值是布尔型(boolean),那么这个方法名应以’?’结尾。
  • include是查找数否包含,index是返回所在位置
  • swapcase是逐字母的进行大小写切换
  • sub和gsub的区别是,sub只替换匹配的到的第一个,而gsub则全局替换
  • 在Ruby里,你可以通过左右加斜杠(/)的方式来指定正则表达式

1.2.5 判断语句(if,unless)

irb(main):031:0> x=3 => 3 irb(main):032:0> if x==4 irb(main):033:1> puts 'hello' irb(main):034:1> end => nil irb(main):035:0> unless x == 4 irb(main):036:1> puts 'hello' irb(main):037:1> end hello
=> nil
  • 除了没有括号和分号外,if的用法看起来没有什么明显区别,当然有一点需要注意,使用if的块模式时,需要在结尾使用end.
  • unless需要特殊记忆一下,这个词我们不能理解为除非,应该理解为如果..不(if not),所以unless x == 4我们一定不能理解为除非x等于4,理解为如果x不等于4更合理一些(unless对我来说太奇怪了,我宁愿使用!或者not).

  • 其实在语义简单的情况下,我们也可以使用行模式:

irb(main):038:0> puts 'hello' if not x==4 hello
=> nil irb(main):039:0> puts 'hello' if x==4 => nil irb(main):040:0> puts 'hello' unless x==4 hello
=> nil
  • 尽管在C家族语言中这种写法被严格禁止(破坏代码可读可维护性),但是在ruby中行模式的写法的确使代码更清晰(这可能因为是没有了括号和分号,ruby读起来更像是自然语言).
  • 从上面代码我们也可以看出来,not是有语义的. and(也可写为&&)是逻辑与,or(也可写为||)是逻辑或.
  • 多说一句,and和or都是短路求值,如果我们不想使用短路求值,可以使用符号&和| (和java,C#类似,和C++略有不同,因为C++没有非短路求值).
irb(main):052:0>  puts 'hello' if 0 hello
=> nil irb(main):053:0>  puts 'hello' if true hello
=> nil irb(main):054:0>  puts 'hello' if 1 hello
=> nil irb(main):055:0>  puts 'hello' if 'ss' (irb):55: warning: string literal in condition
hello
=> nil irb(main):056:0>  puts 'hello' if false => nil irb(main):058:0>  puts 'hello' if nil => nil 
  • 从上面这一连串的if判断我们可以看到,在Ruby中,除了nil和false外,一切值都代表true,即使是0!

1.2.6 循环语句(while,until)

irb(main):041:0> x
=> 3 irb(main):042:0> x = x-1 until x==1
=> nil irb(main):043:0> x
=> 1 irb(main):044:0> until x==5
irb(main):045:1> x=x+1
irb(main):046:1> end
=> nil irb(main):047:0> x
=> 5

上面我们分别展示了until循环的单行模式和块模式写法. 
while的用法基本一致:

>> x = x + 1 while x < 10
=> nil >> x
=> 10

1.2.7 区间

区间大概可以算是Ruby中的一个语法糖。先看下使用:

irb(main):024:0> (0..9) => 0..9 irb(main):025:0> (0..9).class => Range
irb(main):027:0> (0..9).size => 10 irb(main):032:0> (0..9).include?(9) => true irb(main):034:0> (0...9).to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8]
irb(main):035:0> (0..9).to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):038:0> (0..9).reject{|i|i<5} => [5, 6, 7, 8, 9]
irb(main):039:0> (0..3).each do |i| puts i end 0 1 2 3 => 0..3 irb(main):040:0> (0..3).each{|i| puts i*5} 0 5 10 15 => 0..3 irb(main):042:0> (0..9).include?3.14 => true irb(main):043:0> (0..9).cover?3.14 => true irb(main):044:0> ('a'..'z').cover?'ab' => true irb(main):045:0> ('a'..'z').include?'ab' => false
  • Ruby用(0..9)或者(0…9)来表示一个从0到9的区间。区别在于,两个点是闭区间,而三个点则是左闭右开区间。
  • to_a可以将一个区间转化为数组,但是需要注意的是,这并不代表数组中的内容就是区间的所有内容。数组的内容是不连续的,而区间则是一段范围。所以(0..9).include?3.14返回true。
  • each方法可以迭代区间中的值,并可以通过|x|类似语法来使用这个值
  • do end可以包裹一个代码块,同样我们可以使用{}来包裹代码块

1.2.8 鸭子类型

irb(main):066:0> 4+'one' TypeError: String can't be coerced into Fixnum from (irb):66:in `+' from (irb):66 from /usr/bin/irb:12:in `' irb(main):067:0> 4.class => Fixnum 

从前面的多次实验我们已经很明确,Ruby和C家族的语言一样,是强类型的语言。但是跟其他静态强类型语言又很不相同,看下面的例子:

irb(main):068:0> def add
irb(main):069:1> 4+'one' irb(main):070:1> end => nil
irb(main):071:0> add
TypeError: String can't be coerced into Fixnum from (irb):69:in `+' from (irb):69:in `add' from (irb):71 from /usr/bin/irb:12:in `'

我们使用def定义了一个函数,我们发现在函数体内语句实际上是类型错误的,但是在定义后并没有编译器报错,而是直到执行时,才做了类型检查并且报错。这个概念叫做动态类型,因此Ruby也是一种动态语言。

这对于写程序时会带来一些困扰,因为编译器和工具能捕获的错误变少,更多错误在执行时被暴露。但是,这也带来了更加大的自由,来看下面这段代码:

irb(main):073:0> i=0
=> 0 irb(main):074:0> a=['100',99]
=> ["100", 99, 98.0] irb(main):075:0> while i < 2
irb(main):076:1> puts a[i].to_i
irb(main):077:1> i=i+1
irb(main):078:1> end
100
99
=> nil

上面这段代码,数组中存储了两个类型不同的值,但是我们不需要进行类型转换,直接就可以调用变量的to_i方法而没有引发编译错误。

我们知道,在面向对象设计思想中,有这样一个重要原则:对接口编码,不对实现编码。思考一下上面的逻辑我们用java如何实现:我们约定一个实现了to_i的接口,不同类来实现这个接口,这些类的实例存入容器中,依次取出,调用它们的to_i方法。

对比上面我们就可以看出区别,Ruby根本就没有定义接口,也没有强制a存储数据的类型,就直接调用了数据的to_i方法!这也就是著名的鸭子类型的概念:一个类型是什么不是取决于它类型的实体,而是他可以做什么。或者我们使用更通俗的谚语来解释:

从这点我们可以看出来Ruby是一种相当自由的语言。

1.3 DAY1小结

第一天的探索就到这里,我们稍微总结一下:

  • Ruby是一门解释型语言。
  • 一切皆为对象,且易于获取对象的任何信息,如对象的各方法及所属类。
  • 它是鸭子类型的,且行为通常和强类型语言毫无二致。

1.4 实践

基于第一天的学习写了一个简单的程序,写了一个猜随机数的程序,根据输入来告诉用户猜大了还是猜小了。如果用户输入exit则退出。

puts 'gusse the num(0~9)' random = rand(10).to_i while true i = gets if i.start_with?'exit' break end
if i.to_i==random puts 'you get the right num!' break
elsif i.to_i<random puts 'small!' else puts 'big!' end end

基本上使用的都是前面提到的知识。需要额外注意的有: 
- rand(10)是生成0~9的随机数 
- gets是读取键盘输入的字符串 
elsif是ruby中else if的写法 
- break可以跳出循环
文章转自书籍装帧http://www.cmxiaodou.com/task/zhuangzhen

09-04 06:56