Ruby七天入门(2 函数,数组和类)


DAY 2

第二天学习继续,今天重点学习函数,集合和类等编程的基本要素。

2.1 函数

2.1.1 简单定义

<code class="hljs ruby has-numbering"> <span class="hljs-function"><span class="hljs-keyword">def</span> </span>tell_me
 puts <span class="hljs-keyword">true</span>
 <span class="hljs-keyword">end</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
  • 定义一个简单的函数(无参无返回值)很简单,使用def end包裹函数体即可。

2.1.2 参数

<code class="hljs ruby has-numbering"><span class="hljs-function"><span class="hljs-keyword">def</span> </span>tell_me(a)
puts a
<span class="hljs-keyword">end</span>
tell_me <span class="hljs-number">1</span>
<span class="hljs-number">1</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></ul>
  • 使用参数和其他语言类似,加括号加变量名即可。
2.1.2.1 参数默认值

同样可以指定参数默认值:

<code class="hljs haml has-numbering">def tell_me(a='1',b)
puts a
puts b
end
=<span class="ruby">> <span class="hljs-keyword">nil</span>
</span>tell_me 2
1
2
=<span class="ruby">> <span class="hljs-keyword">nil</span>
</span>tell_me 3,4
3
4
=<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><li>12</li><li>13</li></ul>

我们看到指定默认值的方式跟其他语言类似。

有些苦恼的是,看起来我们需要记住每一个函数的参数数量和含义。

2.1.2.2 可变参数

Ruby同样支持可变参数,而且因为不受类型的限制,使用相当自由:

<code class="hljs ruby has-numbering"><span class="hljs-function"><span class="hljs-keyword">def</span> </span>test(*tt)
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>...tt.length
        puts tt[i]
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
=> <span class="hljs-keyword">nil</span>
test <span class="hljs-number">1</span>,<span class="hljs-number">2</span>
<span class="hljs-number">1</span>
<span class="hljs-number">2</span>
=> <span class="hljs-number">0</span>...<span class="hljs-number">2</span>
test <span class="hljs-string">'a'</span>
a
=> <span class="hljs-number">0</span>...<span class="hljs-number">1</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></ul>
  • 我们看到只需要将参数前加*即可,收到的参数就将是一个数组。

2.1.3 返回值

2.1.3.1 默认返回值

  • 昨天的学习里看到过,其实所有的Ruby语句都有返回值,那么其实我们及时不给函数指定返回值,函数也会返回他执行的最后一个语句的值。
    看下面的例子:
<code class="hljs haml has-numbering">def give_me
true
end
=<span class="ruby">> <span class="hljs-keyword">nil</span>
</span>
i=give_me
=<span class="ruby">> <span class="hljs-keyword">true</span>
</span>
i
=<span class="ruby">> <span class="hljs-keyword">true</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></ul>

这个函数我们并没有指定返回值,但是函数还是返回了最后执行的语句true的值。

2.1.3.2 return语句

<code class="hljs php has-numbering">$ irb
def test
a=<span class="hljs-number">1</span>
b=<span class="hljs-number">2</span>
<span class="hljs-keyword">return</span> a,b
end
=> nil
<span class="hljs-keyword">var</span>=test
=> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>]
<span class="hljs-keyword">var</span>.class
=> <span class="hljs-keyword">Array</span>
<span class="hljs-keyword">var</span>
=> [<span class="hljs-number">1</span>, <span class="hljs-number">2</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></ul>
  • Ruby可以通过return语句指定返回值,而且跟C家族语言不同的是,Ruby可以同时返回多个返回值。

  • 因为动态语言的特性,Ruby看起来如此自由,但是看起来这就更要求调用者对他们的调用负责。

2.2 代码块和yield

2.2.1 代码块的使用

代码块是没有名字的函数。

<code class="hljs perl has-numbering"><span class="hljs-number">3</span>.<span class="hljs-keyword">times</span>{puts <span class="hljs-string">'hi'</span>}</code><ul style="display: block;" class="pre-numbering"><li>1</li></ul>
  • times是Fixnum类的方法,它可以执行后面的代码块n次。
  • 后面大括号中内容就是代码块,代码块既可以用{}来包裹,也可以用do/end来包裹,就像下面的的代码。
<code class="hljs livecodeserver has-numbering"><span class="hljs-number">3.</span>times <span class="hljs-built_in">do</span>
puts <span class="hljs-string">'hello'</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></ul>

昨天在区间一节中提到的each函数后面其实也是代码块:

<code class="hljs livecodeserver has-numbering">names=[<span class="hljs-string">'lee'</span>,<span class="hljs-string">'tom'</span>,<span class="hljs-string">'jim'</span>]
names.<span class="hljs-keyword">each</span>{|<span class="hljs-operator">a</span>| puts <span class="hljs-operator">a</span>}</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li></ul>

2.2.2 yield执行代码块

下面我们来看下自定义的方法来执行代码块:

<code class="hljs matlab has-numbering">def my_times(<span class="hljs-built_in">i</span>=<span class="hljs-number">5</span>)
    <span class="hljs-keyword">while</span> <span class="hljs-built_in">i</span>><span class="hljs-number">0</span>
        <span class="hljs-built_in">i</span>=<span class="hljs-built_in">i</span>-<span class="hljs-number">1</span>
        yield
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

my_times(<span class="hljs-number">3</span>)<span class="hljs-cell">{puts <span class="hljs-string">'a'</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>

我们看到这个函数根据传入参数,调用了一定数量的代码块。

  • 函数中定义的yield表示执行代码块中的代码。

2.2.3 代码块作为函数参数

我们也可以将代码块作为参数一直传递下去。

<code class="hljs oxygene has-numbering">def call_block(&<span class="hljs-keyword">block</span>)
    <span class="hljs-keyword">block</span>.call
<span class="hljs-keyword">end</span>

def pass_block(&<span class="hljs-keyword">block</span>)
    call_block(&<span class="hljs-keyword">block</span>)
<span class="hljs-keyword">end</span>

pass_block<span class="hljs-comment">{puts 'hello'}</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></ul>
  • 在Ruby中,参数名之前加一个“&”,表示将代码块作为闭包传递给函数。闭包就是把函数以及变量包起来,使得变量的生存周期延长。

2.3 数组

<code class="hljs bash has-numbering">animals = [<span class="hljs-string">'lions'</span>, <span class="hljs-string">'tigers'</span>, <span class="hljs-string">'bears'</span>]
puts animals[<span class="hljs-number">1</span>]
puts animals[-<span class="hljs-number">1</span>]
puts animals[<span class="hljs-number">0</span>..<span class="hljs-number">1</span>]</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
  • 上面这段代码有个语法糖,-1表示返回倒数第一个元素;当然1和其他语言一样,表示第二个元素
  • animals[0..1]用了昨天学过的区间,表示从0到1个元素
<code class="hljs haml has-numbering">irb(main):002:0> [].class
=<span class="ruby">> <span class="hljs-constant">Array</span>
</span>irb(main):003:0> a =[]
=<span class="ruby">> []
</span>irb(main):004:0> a[1]
=<span class="ruby">> <span class="hljs-keyword">nil</span>
</span>irb(main):005:0> b[1]
NameError: undefined local variable or method `b' for main:Object
        from (irb):5
        from /usr/bin/irb:12:in `<main>'
irb(main):006:0> a[1] = 1
=<span class="ruby">> <span class="hljs-number">1</span>
</span>irb(main):007:0> a[0] = 'zero'
=<span class="ruby">> <span class="hljs-string">"zero"</span>
</span>irb(main):009:0> a[2]=['2','3',[4,5]]
=<span class="ruby">> [<span class="hljs-string">"2"</span>, <span class="hljs-string">"3"</span>, [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]]
</span>irb(main):010:0> a
=<span class="ruby">> [<span class="hljs-string">"zero"</span>, <span class="hljs-number">1</span>, [<span class="hljs-string">"2"</span>, <span class="hljs-string">"3"</span>, [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]]]
</span>irb(main):011:0> a[2][2]
=<span class="ruby">> [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
</span>irb(main):012:0> a[2][2][1]
=<span class="ruby">> <span class="hljs-number">5</span>
</span>irb(main):021:0> a=[]
=<span class="ruby">> []
</span>irb(main):022:0> a[1]=8
=<span class="ruby">> <span class="hljs-number">8</span>
</span>irb(main):023:0> a[3]=6
=<span class="ruby">> <span class="hljs-number">6</span>
</span>irb(main):024:0> a
=<span class="ruby">> [<span class="hljs-keyword">nil</span>, <span class="hljs-number">8</span>, <span class="hljs-keyword">nil</span>, <span class="hljs-number">6</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><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></ul>

比起大多数语言的数组,Ruby的数组使用很自由,从上面这些代码可以看出来。

  • 数组元素不必有相同类型
  • 可以只定义部分数组元素,其余位置将默认为nil值
  • 需要注意的是,在给数组元素赋值时,需要首先使用a =[]类似语法让a的类型变为数组类型,否则出现上面直接运行 b[1]时报的错误
<code class="hljs haml has-numbering">irb(main):025:0> a.push(4)
=<span class="ruby">> [<span class="hljs-keyword">nil</span>, <span class="hljs-number">8</span>, <span class="hljs-keyword">nil</span>, <span class="hljs-number">6</span>, <span class="hljs-number">4</span>]
</span>irb(main):026:0> a.pop
=<span class="ruby">> <span class="hljs-number">4</span>
</span>irb(main):027:0> a
=<span class="ruby">> [<span class="hljs-keyword">nil</span>, <span class="hljs-number">8</span>, <span class="hljs-keyword">nil</span>, <span class="hljs-number">6</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>

数组同样支持push和pop,栈顶位于数组尾部。

2.3.4 散列表

散列表就是键值对,对应java里面的map容器。

<code class="hljs php has-numbering">irb(main):<span class="hljs-number">032</span>:<span class="hljs-number">0</span>> map={<span class="hljs-number">1</span>=><span class="hljs-string">'one'</span>,<span class="hljs-number">2</span>=><span class="hljs-string">'two'</span>}
=> {<span class="hljs-number">1</span>=><span class="hljs-string">"one"</span>, <span class="hljs-number">2</span>=><span class="hljs-string">"two"</span>}
irb(main):<span class="hljs-number">033</span>:<span class="hljs-number">0</span>> map
=> {<span class="hljs-number">1</span>=><span class="hljs-string">"one"</span>, <span class="hljs-number">2</span>=><span class="hljs-string">"two"</span>}
irb(main):<span class="hljs-number">034</span>:<span class="hljs-number">0</span>> map[<span class="hljs-number">1</span>]
=> <span class="hljs-string">"one"</span>
irb(main):<span class="hljs-number">035</span>:<span class="hljs-number">0</span>> map[<span class="hljs-number">3</span>]
=> nil</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>

其实和数组类似,关键的不同就在于一个=>符号,符号前面是键,后面是值。

<code class="hljs php has-numbering">map={<span class="hljs-number">1</span>=><span class="hljs-string">'one'</span>,<span class="hljs-number">2</span>=><span class="hljs-string">'two'</span>}
a = map.to_a
puts a</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
  • 散列表可以转化为数组:其中每个元素是一个key, value组成的数组
<code class="hljs haml has-numbering">map.each { |k,v| p "#{<span class="ruby">k}</span>=>#{<span class="ruby">v}</span>"  }</code><ul style="display: block;" class="pre-numbering"><li>1</li></ul>

散列表同样可以遍历

2.5 类

所有的类都有一个共同的祖先,BasicObject。

<code class="hljs ruby has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TreeTest</span></span>
<span class="hljs-keyword">attr_accessor</span> <span class="hljs-symbol">:children</span>,<span class="hljs-symbol">:node_name</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> </span>initialize(name,children=[])
    <span class="hljs-variable">@children</span> = children
    <span class="hljs-variable">@node_name</span> = name
<span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

ruby_tree = <span class="hljs-constant">Tree</span>.new(<span class="hljs-string">"ruby"</span>,[<span class="hljs-constant">Tree</span>.new(<span class="hljs-string">'1'</span>),<span class="hljs-constant">Tree</span>.new(<span class="hljs-string">'2'</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>

上面代码定义了一个简单的类。

  • 类命名一般使用骆驼命名法,变量和方法名采用小写下划线命名法,而常量采用全大写形式;用于逻辑测试的函数一般用?结尾
  • 实例变量前需要加@(类似java的this?),而类变量前需要加@@(类似java的类名?)
  • attr关键字可用来定义实例变量。它有几种版本,其中最常用的版本是attr和attr_accessor。attr定义实例变量和访问变量的同名方法,而attr_accessor定义实例变量、访问方法和设置方法。
  • initialize方法有特殊含义,类在初始化一个新对象的时候,会调用这个方法
  • 类初始化时采用类名加.new的方法来初始化

2.6 小结

今天主要学习了Ruby的函数,类,数组的基本使用,最大的感触是Ruby的实现充满了符合直觉的特性,在掌握了基本语法后,很多代码只需要按照尝试着写就可以执行。

2.7实践

今天实践在前面Tree类的基础上加上遍历访问的功能,同时我修改了初始化方法,接受散列表和数组嵌套的结构:

<code class="hljs ruby has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tree</span></span>
<span class="hljs-keyword">attr_accessor</span> <span class="hljs-symbol">:children</span>,<span class="hljs-symbol">:node_name</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> </span>initialize(map={})
    <span class="hljs-variable">@children</span> = []
    map.each <span class="hljs-keyword">do</span> |k,v| 
        <span class="hljs-variable">@node_name</span> = k
        v.each { |key,value|  <span class="hljs-variable">@children</span>.push(<span class="hljs-constant">Tree</span>.new({key=>value}))} <span class="hljs-keyword">if</span> v!=<span class="hljs-keyword">nil</span>
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> </span>visit_all(&block)
    visit(&block)
    children.each{|c| c.visit_all(&block)}
<span class="hljs-keyword">end</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> </span>visit(&block)
    block.call(<span class="hljs-keyword">self</span>)
<span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

ruby_tree = <span class="hljs-constant">Tree</span>.new({<span class="hljs-string">'grandpa'</span> => { <span class="hljs-string">'dad'</span> => {<span class="hljs-string">'child 1'</span> => {}, <span class="hljs-string">'child 2'</span> => {} }, <span class="hljs-string">'uncle'</span>=> {<span class="hljs-string">'child 3'</span> => {}, <span class="hljs-string">'child 4'</span> => {} } } } )

ruby_tree.visit {|node| puts node.node_name}
ruby_tree.visit_all {|node| puts node.node_name}</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></ul>

visit方法传递了代码块,调用了代码块并用self做参数(所以看起来代码块是通过这种方式获得参数?),其实就是打印了调用实例的node_name。
visit_all先对当前节点调用了visit方法,然后对子节点进行了递归。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值