多年前就很想学习一下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 解释执行
<code class="language-RUBY hljs ruby has-numbering">irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">001</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span>> puts <span class="hljs-string">'hello,world'</span> hello,world => <span class="hljs-keyword">nil</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
- 输入后立刻得到反馈,说明ruby是可以解释执行的,而不需要编译成字节码.
1.2.2 更自由的变量
<code class="hljs haml has-numbering">irb(main):002:0> language = 'RUBY' =<span class="ruby">> <span class="hljs-string">"RUBY"</span> </span>irb(main):004:0* puts "hello,#{<span class="ruby">language}</span>" hello,RUBY =<span class="ruby">> <span class="hljs-keyword">nil</span> </span>irb(main):005:0> puts 'hello,#{<span class="ruby">language}</span>' hello,#{<span class="ruby">language}</span> =<span class="ruby">> <span class="hljs-keyword">nil</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
上面这段尝试可以发现:
- ruby中不需要提前声明变量,变量可以直接被初始化和赋值(这样意味着变量的类型可以随着赋值的不同而随时改变)
- 所有的ruby语句都有返回值
- #{}可以求得变量的值(占位符并不局限于变量。任意放置在#{}中的合法Ruby代码都将被求值,并被替换为求值结果插入到原位置)
- 目前可以看到有两种格式的字符串,一种是单引号包括的,这种单引号是不加改动的解释;另外一种是双引号包括的,会引发字符串替换.
1.2.3 万物皆对象
<code class="hljs haml has-numbering">irb(main):008:0> 4 =<span class="ruby">> <span class="hljs-number">4</span> </span>irb(main):009:0> 4.class =<span class="ruby">> <span class="hljs-constant">Fixnum</span> </span>irb(main):010:0> 4.methods =<span class="ruby">> [<span class="hljs-symbol">:to_s</span>, <span class="hljs-symbol">:inspect</span>, <span class="hljs-symbol">:-@</span>, <span class="hljs-symbol">:+</span>, <span class="hljs-symbol">:-</span>, <span class="hljs-symbol">:*</span>, <span class="hljs-symbol">:/</span>, <span class="hljs-symbol">:div</span>, <span class="hljs-symbol">:%</span>, <span class="hljs-symbol">:modulo</span>, <span class="hljs-symbol">:divmod</span>, <span class="hljs-symbol">:fdiv</span>, <span class="hljs-symbol">:**</span>, <span class="hljs-symbol">:abs</span>, <span class="hljs-symbol">:magnitude</span>, ...]</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
上面这段可以说明更多的问题:
- 可以看到在ruby中万物皆对象,即使是一个数字
- .methods可以打印出这个对象支持的所有方法数组
- Ruby用[]表示数组
<code class="hljs haml has-numbering">irb(main):012:0> -4.abs =<span class="ruby">> <span class="hljs-number">4</span> </span>irb(main):014:0> 4.equal?4 =<span class="ruby">> <span class="hljs-keyword">true</span> </span>irb(main):015:0> -4.abs.equal?4 =<span class="ruby">> <span class="hljs-keyword">true</span> </span>irb(main):016:0> -4.equal?4 =<span class="ruby">> <span class="hljs-keyword">false</span> </span>irb(main):020:0> 4.instance_of?Fixnum =<span class="ruby">> <span class="hljs-keyword">true</span> </span>irb(main):025:0> 4.!=4.class =<span class="ruby">> <span class="hljs-keyword">true</span> </span>irb(main):027:0> (4.!=4).class =<span class="ruby">> <span class="hljs-constant">FalseClass</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>
- Ruby中使用带参数方法不需要括号,直接在方法后面
- RUBY中存在优先级,括号可以影响优先级
1.2.4 字符串操作
<code class="hljs coffeescript has-numbering">irb(main):<span class="hljs-number">001</span>:<span class="hljs-number">0</span>> <span class="hljs-string">'size'</span>.length<span class="hljs-function"> =></span> <span class="hljs-number">4</span> irb(main):<span class="hljs-number">004</span>:<span class="hljs-number">0</span>> <span class="hljs-string">'size'</span>.include?<span class="hljs-string">'si'</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">005</span>:<span class="hljs-number">0</span>> <span class="hljs-string">"Ruby is a beautiful language"</span>.start_with? <span class="hljs-string">"Ruby"</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">006</span>:<span class="hljs-number">0</span>> <span class="hljs-string">"I can't work with any other language but Ruby"</span>.end_with? <span class="hljs-string">'Ruby'</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">007</span>:<span class="hljs-number">0</span>> <span class="hljs-string">'size'</span>.index<span class="hljs-string">'i'</span><span class="hljs-function"> =></span> <span class="hljs-number">1</span> irb(main):<span class="hljs-number">008</span>:<span class="hljs-number">0</span>> <span class="hljs-string">'size'</span>.upcase<span class="hljs-function"> =></span> <span class="hljs-string">"SIZE"</span> irb(main):<span class="hljs-number">009</span>:<span class="hljs-number">0</span>> <span class="hljs-string">'SIZE'</span>.downcase<span class="hljs-function"> =></span> <span class="hljs-string">"size"</span> irb(main):<span class="hljs-number">010</span>:<span class="hljs-number">0</span>> <span class="hljs-string">"ThiS iS A vErY ComPlEx SenTeNcE"</span>.swapcase<span class="hljs-function"> =></span> <span class="hljs-string">"tHIs Is a VeRy cOMpLeX sENtEnCe"</span> irb<span class="hljs-function"><span class="hljs-params">(main)</span>:011:0> "<span class="hljs-title">I</span> <span class="hljs-title">can</span>'<span class="hljs-title">t</span> <span class="hljs-title">work</span> <span class="hljs-title">with</span> <span class="hljs-title">any</span> <span class="hljs-title">other</span> <span class="hljs-title">language</span> <span class="hljs-title">but</span> <span class="hljs-title">Ruby</span>".<span class="hljs-title">split</span><span class="hljs-params">(<span class="hljs-string">' '</span>)</span> =></span> [<span class="hljs-string">"I"</span>, <span class="hljs-string">"can't"</span>, <span class="hljs-string">"work"</span>, <span class="hljs-string">"with"</span>, <span class="hljs-string">"any"</span>, <span class="hljs-string">"other"</span>, <span class="hljs-string">"language"</span>, <span class="hljs-string">"but"</span>, <span class="hljs-string">"Ruby"</span>] irb<span class="hljs-function"><span class="hljs-params">(main)</span>:013:0> "<span class="hljs-title">I</span> <span class="hljs-title">can</span>'<span class="hljs-title">t</span> <span class="hljs-title">work</span> <span class="hljs-title">with</span> <span class="hljs-title">any</span> <span class="hljs-title">other</span> <span class="hljs-title">language</span> <span class="hljs-title">but</span> <span class="hljs-title">Ruby</span>.<span class="hljs-title">I</span> <span class="hljs-title">am</span> <span class="hljs-title">happy</span>.".<span class="hljs-title">sub</span><span class="hljs-params">(<span class="hljs-string">'I'</span>,<span class="hljs-string">'We'</span>)</span> =></span> <span class="hljs-string">"We can't work with any other language but Ruby.I am happy."</span> irb<span class="hljs-function"><span class="hljs-params">(main)</span>:014:0> "<span class="hljs-title">I</span> <span class="hljs-title">can</span>'<span class="hljs-title">t</span> <span class="hljs-title">work</span> <span class="hljs-title">with</span> <span class="hljs-title">any</span> <span class="hljs-title">other</span> <span class="hljs-title">language</span> <span class="hljs-title">but</span> <span class="hljs-title">Ruby</span>.<span class="hljs-title">I</span> <span class="hljs-title">am</span> <span class="hljs-title">happy</span>.".<span class="hljs-title">gsub</span><span class="hljs-params">(<span class="hljs-string">'I'</span>,<span class="hljs-string">'We'</span>)</span> =></span> <span class="hljs-string">"We can't work with any other language but Ruby.We am happy."</span> irb<span class="hljs-function"><span class="hljs-params">(main)</span>:015:0> '<span class="hljs-title">RubyMonk</span>'.<span class="hljs-title">gsub</span><span class="hljs-params">(<span class="hljs-regexp">/[aeiou]/</span>,<span class="hljs-string">'1'</span>)</span> =></span> <span class="hljs-string">"R1byM1nk"</span> irb<span class="hljs-function"><span class="hljs-params">(main)</span>:017:0> '<span class="hljs-title">RubyMonk</span> <span class="hljs-title">Is</span> <span class="hljs-title">Pretty</span> <span class="hljs-title">Brilliant</span>'.<span class="hljs-title">gsub</span><span class="hljs-params">(<span class="hljs-regexp">/[A-Z]/</span>,<span class="hljs-string">'0'</span>)</span> =></span> <span class="hljs-string">"0uby0onk 0s 0retty 0rilliant"</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>
上面这些语句基本列出了主要的字符串操作函数,大多数语句的含义基本都是不言而喻的。有以下少数几点需要注意:
- 依照Ruby惯例,如果某个方法返回值是布尔型(boolean),那么这个方法名应以’?’结尾。
- include是查找数否包含,index是返回所在位置
- swapcase是逐字母的进行大小写切换
- sub和gsub的区别是,sub只替换匹配的到的第一个,而gsub则全局替换
- 在Ruby里,你可以通过左右加斜杠(/)的方式来指定正则表达式
1.2.5 判断语句(if,unless)
<code class="hljs ruby has-numbering">irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">031</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span>> x=<span class="hljs-number">3</span> => <span class="hljs-number">3</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">032</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span>> <span class="hljs-keyword">if</span> x==<span class="hljs-number">4</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">033</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>> puts <span class="hljs-string">'hello'</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">034</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>> <span class="hljs-keyword">end</span> => <span class="hljs-keyword">nil</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">035</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span>> <span class="hljs-keyword">unless</span> x == <span class="hljs-number">4</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">036</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>> puts <span class="hljs-string">'hello'</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">037</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>> <span class="hljs-keyword">end</span> hello => <span class="hljs-keyword">nil</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>
- 除了没有括号和分号外,if的用法看起来没有什么明显区别,当然有一点需要注意,使用if的块模式时,需要在结尾使用end.
-
unless需要特殊记忆一下,这个词我们不能理解为除非,应该理解为如果..不(if not),所以unless x == 4我们一定不能理解为除非x等于4,理解为如果x不等于4更合理一些(unless对我来说太奇怪了,我宁愿使用!或者not).
-
其实在语义简单的情况下,我们也可以使用行模式:
<code class="hljs ruby has-numbering">irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">03</span>8<span class="hljs-symbol">:</span><span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> x==<span class="hljs-number">4</span> hello => <span class="hljs-keyword">nil</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">03</span>9<span class="hljs-symbol">:</span><span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> x==<span class="hljs-number">4</span> => <span class="hljs-keyword">nil</span> irb(main)<span class="hljs-symbol">:</span><span class="hljs-number">040</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">unless</span> x==<span class="hljs-number">4</span> hello => <span class="hljs-keyword">nil</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
- 尽管在C家族语言中这种写法被严格禁止(破坏代码可读可维护性),但是在ruby中行模式的写法的确使代码更清晰(这可能因为是没有了括号和分号,ruby读起来更像是自然语言).
- 从上面代码我们也可以看出来,not是有语义的. and(也可写为&&)是逻辑与,or(也可写为||)是逻辑或.
- 多说一句,and和or都是短路求值,如果我们不想使用短路求值,可以使用符号&和| (和java,C#类似,和C++略有不同,因为C++没有非短路求值).
<code class="hljs lua has-numbering">irb(main):<span class="hljs-number">052</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-number">0</span> hello => <span class="hljs-keyword">nil</span> irb(main):<span class="hljs-number">053</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">true</span> hello => <span class="hljs-keyword">nil</span> irb(main):<span class="hljs-number">054</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-number">1</span> hello => <span class="hljs-keyword">nil</span> irb(main):<span class="hljs-number">055</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-string">'ss'</span> (irb):<span class="hljs-number">55</span>: warning: <span class="hljs-built_in">string</span> literal <span class="hljs-keyword">in</span> condition hello => <span class="hljs-keyword">nil</span> irb(main):<span class="hljs-number">056</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">false</span> => <span class="hljs-keyword">nil</span> irb(main):<span class="hljs-number">058</span>:<span class="hljs-number">0</span>> puts <span class="hljs-string">'hello'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">nil</span> => <span class="hljs-keyword">nil</span> </code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>
- 从上面这一连串的if判断我们可以看到,在Ruby中,除了nil和false外,一切值都代表true,即使是0!
1.2.6 循环语句(while,until)
<code class="hljs haml has-numbering">irb(main):041:0> x =<span class="ruby">> <span class="hljs-number">3</span> </span>irb(main):042:0> x = x-1 until x==1 =<span class="ruby">> <span class="hljs-keyword">nil</span> </span>irb(main):043:0> x =<span class="ruby">> <span class="hljs-number">1</span> </span>irb(main):044:0> until x==5 irb(main):045:1> x=x+1 irb(main):046:1> end =<span class="ruby">> <span class="hljs-keyword">nil</span> </span>irb(main):047:0> x =<span class="ruby">> <span class="hljs-number">5</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>
上面我们分别展示了until循环的单行模式和块模式写法.
while的用法基本一致:
<code class="hljs haml has-numbering">>> x = x + 1 while x < 10 =<span class="ruby">> <span class="hljs-keyword">nil</span> </span>>> x =<span class="ruby">> <span class="hljs-number">10</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
1.2.7 区间
区间大概可以算是Ruby中的一个语法糖。先看下使用:
<code class="hljs coffeescript has-numbering">irb<span class="hljs-function"><span class="hljs-params">(main)</span>:024:0> <span class="hljs-params">(<span class="hljs-number">0.</span><span class="hljs-number">.9</span>)</span> =></span> <span class="hljs-number">0.</span><span class="hljs-number">.9</span> irb(main):<span class="hljs-number">025</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).class<span class="hljs-function"> =></span> Range irb(main):<span class="hljs-number">027</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).size<span class="hljs-function"> =></span> <span class="hljs-number">10</span> irb<span class="hljs-function"><span class="hljs-params">(main)</span>:032:0> <span class="hljs-params">(<span class="hljs-number">0.</span><span class="hljs-number">.9</span>)</span>.<span class="hljs-title">include</span>?<span class="hljs-params">(<span class="hljs-number">9</span>)</span> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">034</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span>.<span class="hljs-number">.9</span>).to_a<span class="hljs-function"> =></span> [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>] irb(main):<span class="hljs-number">035</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).to_a<span class="hljs-function"> =></span> [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>] irb(main):<span class="hljs-number">038</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).reject{|i|i<<span class="hljs-number">5</span>}<span class="hljs-function"> =></span> [<span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>] irb(main):<span class="hljs-number">039</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.3</span>).each <span class="hljs-keyword">do</span> |i| puts i end <span class="hljs-number">0</span> <span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">3</span><span class="hljs-function"> =></span> <span class="hljs-number">0.</span><span class="hljs-number">.3</span> irb(main):<span class="hljs-number">040</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.3</span>).each{|i| puts i*<span class="hljs-number">5</span>} <span class="hljs-number">0</span> <span class="hljs-number">5</span> <span class="hljs-number">10</span> <span class="hljs-number">15</span><span class="hljs-function"> =></span> <span class="hljs-number">0.</span><span class="hljs-number">.3</span> irb(main):<span class="hljs-number">042</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).include?<span class="hljs-number">3.14</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">043</span>:<span class="hljs-number">0</span>> (<span class="hljs-number">0.</span><span class="hljs-number">.9</span>).cover?<span class="hljs-number">3.14</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">044</span>:<span class="hljs-number">0</span>> (<span class="hljs-string">'a'</span>..<span class="hljs-string">'z'</span>).cover?<span class="hljs-string">'ab'</span><span class="hljs-function"> =></span> <span class="hljs-literal">true</span> irb(main):<span class="hljs-number">045</span>:<span class="hljs-number">0</span>> (<span class="hljs-string">'a'</span>..<span class="hljs-string">'z'</span>).include?<span class="hljs-string">'ab'</span><span class="hljs-function"> =></span> <span class="hljs-literal">false</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>
- Ruby用(0..9)或者(0…9)来表示一个从0到9的区间。区别在于,两个点是闭区间,而三个点则是左闭右开区间。
- to_a可以将一个区间转化为数组,但是需要注意的是,这并不代表数组中的内容就是区间的所有内容。数组的内容是不连续的,而区间则是一段范围。所以(0..9).include?3.14返回true。
- each方法可以迭代区间中的值,并可以通过|x|类似语法来使用这个值
- do end可以包裹一个代码块,同样我们可以使用{}来包裹代码块
1.2.8 鸭子类型
<code class="hljs vbnet has-numbering">irb(main):<span class="hljs-number">066</span>:<span class="hljs-number">0</span>> <span class="hljs-number">4</span>+<span class="hljs-comment">'one'</span> TypeError: <span class="hljs-built_in">String</span> can<span class="hljs-comment">'t be coerced into Fixnum</span> <span class="hljs-keyword">from</span> (irb):<span class="hljs-number">66</span>:<span class="hljs-keyword">in</span> `+<span class="hljs-comment">'</span> <span class="hljs-keyword">from</span> (irb):<span class="hljs-number">66</span> <span class="hljs-keyword">from</span> /usr/bin/irb:<span class="hljs-number">12</span>:<span class="hljs-keyword">in</span> `<main><span class="hljs-comment">'</span> irb(main):<span class="hljs-number">067</span>:<span class="hljs-number">0</span>> <span class="hljs-number">4.</span><span class="hljs-keyword">class</span> => Fixnum </code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
从前面的多次实验我们已经很明确,Ruby和C家族的语言一样,是强类型的语言。但是跟其他静态强类型语言又很不相同,看下面的例子:
<code class="hljs vbnet has-numbering">irb(main):<span class="hljs-number">068</span>:<span class="hljs-number">0</span>> def add irb(main):<span class="hljs-number">069</span>:<span class="hljs-number">1</span>> <span class="hljs-number">4</span>+<span class="hljs-comment">'one'</span> irb(main):<span class="hljs-number">070</span>:<span class="hljs-number">1</span>> <span class="hljs-keyword">end</span> => nil irb(main):<span class="hljs-number">071</span>:<span class="hljs-number">0</span>> add TypeError: <span class="hljs-built_in">String</span> can<span class="hljs-comment">'t be coerced into Fixnum</span> <span class="hljs-keyword">from</span> (irb):<span class="hljs-number">69</span>:<span class="hljs-keyword">in</span> `+<span class="hljs-comment">'</span> <span class="hljs-keyword">from</span> (irb):<span class="hljs-number">69</span>:<span class="hljs-keyword">in</span> `add<span class="hljs-comment">'</span> <span class="hljs-keyword">from</span> (irb):<span class="hljs-number">71</span> <span class="hljs-keyword">from</span> /usr/bin/irb:<span class="hljs-number">12</span>:<span class="hljs-keyword">in</span> `<main><span class="hljs-comment">'</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>
我们使用def定义了一个函数,我们发现在函数体内语句实际上是类型错误的,但是在定义后并没有编译器报错,而是直到执行时,才做了类型检查并且报错。这个概念叫做动态类型,因此Ruby也是一种动态语言。
这对于写程序时会带来一些困扰,因为编译器和工具能捕获的错误变少,更多错误在执行时被暴露。但是,这也带来了更加大的自由,来看下面这段代码:
<code class="hljs haml has-numbering">irb(main):073:0> i=0 =<span class="ruby">> <span class="hljs-number">0</span> </span>irb(main):074:0> a=['100',99] =<span class="ruby">> [<span class="hljs-string">"100"</span>, <span class="hljs-number">99</span>, <span class="hljs-number">98.0</span>] </span>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 =<span class="ruby">> <span class="hljs-keyword">nil</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>
上面这段代码,数组中存储了两个类型不同的值,但是我们不需要进行类型转换,直接就可以调用变量的to_i方法而没有引发编译错误。
我们知道,在面向对象设计思想中,有这样一个重要原则:对接口编码,不对实现编码。思考一下上面的逻辑我们用java如何实现:我们约定一个实现了to_i的接口,不同类来实现这个接口,这些类的实例存入容器中,依次取出,调用它们的to_i方法。
对比上面我们就可以看出区别,Ruby根本就没有定义接口,也没有强制a存储数据的类型,就直接调用了数据的to_i方法!这也就是著名的鸭子类型的概念:一个类型是什么不是取决于它类型的实体,而是他可以做什么。或者我们使用更通俗的谚语来解释:
如果像鸭子一样走路,像鸭子一样呱呱叫,那它就是一只鸭子。
从这点我们可以看出来Ruby是一种相当自由的语言。
1.3 DAY1小结
第一天的探索就到这里,我们稍微总结一下:
- Ruby是一门解释型语言。
- 一切皆为对象,且易于获取对象的任何信息,如对象的各方法及所属类。
- 它是鸭子类型的,且行为通常和强类型语言毫无二致。
1.4 实践
基于第一天的学习写了一个简单的程序,写了一个猜随机数的程序,根据输入来告诉用户猜大了还是猜小了。如果用户输入exit则退出。
<code class="hljs livecodeserver has-numbering">puts <span class="hljs-string">'gusse the num(0~9)'</span> <span class="hljs-built_in">random</span> = rand(<span class="hljs-number">10</span>).to_i <span class="hljs-keyword">while</span> <span class="hljs-constant">true</span> i = gets <span class="hljs-keyword">if</span> i.start_with?<span class="hljs-string">'exit'</span> break <span class="hljs-keyword">end if</span> i.to_i==<span class="hljs-built_in">random</span> puts <span class="hljs-string">'you get the right num!'</span> break elsif i.to_i<<span class="hljs-built_in">random</span> puts <span class="hljs-string">'small!'</span> <span class="hljs-keyword">else</span> puts <span class="hljs-string">'big!'</span> <span class="hljs-function"><span class="hljs-keyword">end</span></span> <span class="hljs-function"><span class="hljs-keyword">end</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
基本上使用的都是前面提到的知识。需要额外注意的有:
- rand(10)是生成0~9的随机数
- gets是读取键盘输入的字符串
- elsif是ruby中else if的写法
- break可以跳出循环