Ruby积累

1.Symbol类
2.sort方法
3.reduce方法
4.ARGV和gets方法的区别
5.defined?用法
6.&:first用法
7.四种相等
8.unless用法
9.super用法
10.“!”
11.删除方法
12.“::”
13.IO实例
14.异常处理
15.require方法
16.respond_to?和respond_to_missing?
17.define_method
18.public方法的调用
19.send方法调用
20.模块和类的区别
21.计算行数中的闭包问题
22.表达式的求值顺序
23.case用法
24.map和each的返回值
25.赋值和拷贝

1.Symbol类

1.两种形式:一种是直接冒号加名字,一种是冒号加字符串
2.在一文本中,同一Symbol对象表示的类名,方法名,变量指向同一个Symbol对象
3.对于可变的使用String,不可变的使用Symbol

1.两种形式:一种是直接冒号加名字,一种是冒号加字符串
#下面两种就是Symbol对象的两种表现形式
:test
:"test"
#上面的两种形式表示的是同一个对象,就是具有相同的object_id,指向同一个内存地址。
 :test.object_id #=>355868
:"test".object_id #=>355868
#即是名字相同,symbol相同,:test和:“test”是形同的名字,所以他们是相同的symbol。
#但是如果是:@test和:test是不同的名字,所以他们是不同的symbol。
:@test.object_id # 1148868
:test.object_id # 355868
#区别于两个值相同的字符串,他们只是值相同,但不是同一个字符串对象,没有指向同一个内存地址
“test”.object_id  #=> 70114101202320
"test".object_id  #=> 70114107991560

2.在一文本中,同一Symbol对象表示的类名,方法名,变量指向同一个Symbol对象
module One 
  class Fred
  end 
  $f1 = :Fred
end

module Two 
  Fred = 1 
  $f2 = :Fred
end

def Fred()
end
$f3 = :Fred

$f1.object_id #=> 2514190
$f2.object_id #=> 2514190
$f3.object_id #=> 2514190

3.对于可变的使用String,不可变的使用Symbol
String有"[]="方法,Symbol没有这个方法,因为它是不可变的。
使用Symbol方法可以降低内存,因为相同名字的Symbol指向的是同一个对象。

2.sort方法

a = [1,2,3]
a.sort #=>[1,2,3]
a.sort{|x,y|x<=>y} #=>[1,2,3]

a.sort{|x,y|y<=>x} #=>[3,2,1]

#前值和后值做比较(就是x<=>y的形式),如果前者比后者小,则按照[x,y]进行排序,就是所谓升序排列。
#如果是后值和前值做比较(就是y<=>x的形式),就是所谓的降序排列。

3.reduce方法

作用:遍历数组中的每个值进行累加,累加值即是最后的结果。

#只添加symbol
(5..10).reduce(:+) #=>45  遍历每个数进行累加,返回最终的累计值

#添加初始值和symbol
(5..10).reduce(1,:+) #=>46  1是初始值

#添加block,在没有初始值的情况下,数组的第一个值初始值,即sum=5,从第二个值开始累加
#从第二个值进行累加,这是自己的理解
(5..10).inject { |sum, n| sum + n }  #=>45

#添加block和初始值,从初始值开始累加
(5..10).inject(1) { |sum, n| sum + n } #=>46

4.ARGV和gets方法的区别

1.ARGV的用法:

#demo.rb:
puts "首个参数:#{ARGV[0]}"

#在终端执行代码
 demo.rb demo

#结果返回
首个参数:demo


2.gets的用法:
#demo.rb:
puts "首个参数:#{gets()}"

#执行
demo.rb demo  #无效

#执行
demo.rb #回车
demo    # 首个参数:demo

总结:ARGV和gets这两个方法主要的区别是“回车”

5.defined?用法

defined?和super一样,都是关键词,不是方法

1.defined? 是一个特殊的运算符,以方法调用的形式来判断传递的表达式是否已定义。
2.它返回表达式的描述字符串,如果表达式未定义则返回 nil。

#用法一:判断变量是否定义
foo = 42
defined? foo  # => "local-variable"
defined? $_   # => "global-variable"
defined? bar  # => nil(未定义)

#用法二:判断方法是否定义
defined? puts  # => "method"
defined? puts(bar)  # => nil(在这里 bar 未定义)
defined? unpack  # => nil(在这里未定义)

#用法三:判断yield是否可用
若 yield 调用可用,则返回真,具体返回值为字符串 "yield" 
class Base
  def foo
    puts defined? yield
  end
end

a = Base.new
a.foo  # =>nil
a.foo{ this is the block} # => yield

#用法四:判断super是否可用
defined? super,若 super 可被调用,则返回真,具体返回值为字符串 "super" 
class Base
  def foo
  end
end

class Derived < Base
  def foo
    puts defined? super
  end

  def fun
    puts defined? super
  end
end

obj = Derived.new
obj.foo  #=> super
obj.fun  #=> nil

6.&:first用法

array = [["a",5], ["b", 3], ["a",6]]
array.uniq(&:first).sort_by(&:last)

#上面的代码等同于
array.uniq{|a|.a.first}.sort_by{|x|x.last}
#就是按照数据的第一个元素去重,然后按照数组的第二个元素排序

7.四种相等

1."=="表示值形同
2."===",一般在case中,表示某种匹配
3."equal?"是指两个对象的object_id值一样,即是引用同一个对象。
4."eql?"要求值和对象类型都必须相同。

1. "=="表示值形同
#字符串的内容相同
a = "string"
b = "string" + ""
a == b  #=>true
#数值相同
a = 1
b = 1.0
a == b #=>true

2. "===",一般在case中,表示某种匹配
case some_object
when /a regex/ 
# The regex matches
when 2..4 
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned trueend

#上面的代码和下面代码的实现形式:
if /a regex/ === some_object
# The regex matches
elsif (2..4) === some_object 
# some_object is in the range 2..4
elsif lambda {|x| some_crazy_custom_predicate } === some_object 
# the lambda returned trueend

3. "equal?"是指两个对象的object_id值一样,即是引用同一个对象。
obj = "a"
other = obj.dup
obj == other #=> true
obj.equal? other #=> false
obj.equal? obj #=> true

a = "string"
b = "string" + ""
a.object_id #=>70268974328100
b.object_id #=>70268970910720
a == b  #=>true  #a和b的数值相同
a.equal?b #=>false #a和b有不同的object_id

a = 1
b = 1.0
a == b #=>true #=>a和b的数值相同
a.object_id #=>3
b.object_id #=>-36028797018963966 
a.equal?b #=>false  #a和b具有不同的object_id

4. "eql?"要求值和对象类型都必须相同
a = "string"
b = "string"+""
a.eql?b #=>true
#上面的a和b两个值相同,并且属于String类

a = 1
b = 1.0
a.eql?b #=>false
#上面的a和b两个值相同,但是1属于Integer类,b属于Float类

8.unless用法

unless相当于if not ,如果unless后面的语句执行的结果为false,则该语句执行,如果为true,则该语句不执行。

#代码如下所示,当unless后面为false的时:
def demo
  puts "test" unless false
end
demo  #=>这个执行结果为test

#当unless后面为true时:
def demo
  puts "test" unless true
end
demo #=>这个执行结果为nil

9.super用法

super是调用父类方法的执行,但是super和super()的调用结果不同。
1.super()表示不带参数,不把参数带入到父类中。
2.super表示需要将参数带入到父类中,并且执行相应的方法。
3.使用super时,从继承体系中的上一层寻找和当前同名的方法,同样适用于module
4.报错之后,super之后的代码不执行
5.使用super时引发method_missing方法

1.第一种:使用super()方法:
class Foo
  def show
    puts "Foo#show"
  end
end

class Bar < Foo
  def show(text)
    super()
    puts text
  end
end

Bar.new.show("test")
#下面是结果
Foo#show
test
#使用super()方法,不将参数带入到父类的show方法中,父类的show方法也不存在调用参数。

2.第二种:使用super方法:
class Foo
  def show
    puts "Foo#show"
  end
end

class Bar < Foo
  def show(text)
    super
    puts text
  end
end

Bar.new.show("test")
#wrong number of arguments (given 1, expected 0) (ArgumentError)

上面的代码中super方法会将text这个参数传递给父类的show方法,但是父类的方法其实没有参数选项,因此出错。

#代码修正
def show(text)
  puts "#{text}, Foo#show"
end

3.同样适用于module
module One
  def demo
    puts "this is the method one demo"
  end
end

module Two
  include One
  def demo
    super
    puts "this is the method two demo"
  end
end

class A
  include Two
end

obj = A.new
obj.demo
#结果
this is the method one demo
this is the method two demo

4.使用super报错之后不会执行super之后的语句
class Demo
  def method_missing(name, *args, &block)
    super
    puts "this is the method_missing"
  end
end

obj = Demo.new
obj.cc  #undefied method cc
#并且super之后的代码不执行

5.使用super时引发method_missing方法
class Father
  def laugh
    super
  end
end
Father.new.laugh #=>no superclass method `laugh' NoMethodError

#如果在继承体系中定义了method_missing方法,将丢失默认的提示信息
class Father
  def laugh
    super
  end

  def method_missing(method)
    puts "this is the missing method"
  end
end
Father.new.laugh #=> this is the missing method

10.“!”

compact  
#返回了去除了nil的对自身拷贝的数组,但是自身数组其实没有变化
Returns a copy of self with all nil elements removed.

a = ["a","b",nil].compact 
a.compact #=>["a", "b"]
a #=>["a","b",nil]

compact!
#改变了原来的数组
Removes nil elements from the array.
Returns nil if no changes were made, otherwise returns the array.

#如果存在nil,则返回去除了nil的数组
a = ["a","b",nil]
a.compact! #=>["a","b"]
a #=>["a","b"]

#如果不存在nil,则返回nil
a= ["a", "b"].compact! #=>["a", "b"]
a #=>["a","b"]

11.删除方法

两个删除方法,包括undef_method和remove_method方法
1.前者方法会删除所有包括继承来的方法,而后者只删除接受这自己的方法,保留继承的方法
2.这两个方法都是Module类的实例方法,可以在类中直接使用。

class Parent
  def demo
    puts "this is the parent"
  end
end

class Child
  def demo
    puts "this is the child"
  end
end

obj = Child.new
obj.demo #=> "this is the child"

#使用remove_method方法
class Child
  remove_method :demo
end

obj =Child.new
#说明删除了自己的方法,保留了继承的方法
obj.demo #=>"this is the parent"

#使用undef_method方法
class Child
  undef_method :demo
end

obj =Child.new
#说明删除了所有的方法,包括继承来的方法
obj.demo #=>undefined method demo

12."::"

示例:
module Foo
  class Bar
    A = “demo one”
  end

  B = "demo two"

  class Tao
    delf self.method2
      "method2"
    end
  end

  class Zen
    def method2
      "method2"
    end
  end

  class ::FooBar
     def self.method1
       "method1"
     end
  end
end

puts Foo::Bar::A #调用类名
puts Foo::B #调用常量
puts Foo::Tao::method1 #调用类方法
puts Foo::Zen::new::method2 #调用实例方法
FooBar::method1  #::表示 root namespace

#第一种情况:双引号是定义namespace或者叫做scope用的,当使用Foo::Bar的时候,实际上是在找名字叫做Foo的namespace,然后返回里面的Bar参数
这个Bar可以是个常量,可以是个类,可以是个方法(类名和方法名在Ruby中被视为常量)

#第二种情况:“::”还能用来找真正的常量
class Foo
  Bar = "hello"  #常量
  bar = "hello"  #局部变量
end

Foo::Bar #=>"hello"
Foo::bar #=>出错
Foo.Bar #=>出错
Foo.Bar #=>出错

#第三种情况:“::”在开始的位置则表示回到root namespace,不管前面套了几个module,而这个root namespace是Object
puts self #=>main
puts self.class #=> Object

#第四情况:一般情况下是module做为namespace,但是其实class其实也可以作为namespace:
class Externel
#class Internel换成module Internel效果也是一样的
  class Internel
    def self.class_method
      puts "this is the class method"
    end

    def instance_method
      puts "this is the instance method "
    end
  end
end

Externel::Internel.class_method #=>"this is the class method"
Externel::Internel::new::instance_method #=> "this is the instance method"

13.IO实例

#####实例:写Blog
class Blog
  attr_accessor :author, :title, :time, :content
 
  def initialize(author = "blackanger", title, content)
    @author = author
    @title = title
    @content = "#{content}"
    @time = Time.now.strftime("%Y-%m-%d %H:%M:%S")
  end

  def write
    File.open("blog_date", 'a+') do |f|
      enter(f)
      f.write DATA.read
      enter(f)
      f.write @time
      enter(f, 2)
      f.write "Title: #{@title}"
      enter(f, 2)
      f.write "Content:"
      enter(f)
      f.write @content
      enter(f)
    end 
  end

  def self.read
    File.open("blog_date", "r") do |f|
      f.each_line{|el| puts el}
    end
  end

  def enter(f, n=1)
    n.times{f.write "\n"}
  end
end

if ARGV[0] == "read"
  Blog.read
else
  puts "opening the blog data file .."
    
  puts "请输入标题:"
  title = STDIN.gets.chomp

  puts "请输入内容:(输入END结束内容)"
  content = ""
  STDIN.each_line do |str|
    content << str
    break if str.chomp == "END"
  end

  puts "OK,正在写入文件.."
    
  blog = Blog.new(title, content)
  blog.write
   
  puts "提交成功! 下面是您的Blog!"
    
  puts "当前目录:#{__dir__}, 当前文件:#{__FILE__}"
  Blog.read
end
 
__END__
#------
#copyright
#------

14.异常处理

#代码示例
begin
  1/m
  raise "error A"
  #fail "Error"
rescue =>e
  puts "#{e.message}"
  raise "error B"
  m +=1
  retry
else
  puts "test"
ensure 
  puts "must to do"
end

1. begin .. end 语句可以放在方法里面,也可以放在类里面
#如果放在方法里面可以省略保留字begin,end,直接书写rescue和ensure:
def foo
  rescue =>ex
    异常处理
  ensure
    后处理
end
#如果放在类里面,也可以直接使用rescue和ensure,省略begin和end
#但是的话如果类定义途中发生异常,那么异常发生部分后的定义方法就不会再执行,因此一般不在类定义中使用他们

2. 这里几个关键词比如begin,rescue,ensure,retry,raise,fail,else等,其中begin,rescue,ensure,retry,else是保留字,而fail和raise是Kernel的module method,其两者的功能都是一样的,都是抛出相应的内容。
3. ensure的作用是无论上面的代码是否执行,ensure里面的代码都会执行。
4. rescue只接受异常类,而符号=>与hash中的符号的表示意义不一样,这里表示的意思是传递。
5. retry是重新执行这段代码的意思,而这里被重新执行的代码是begin到rescue这段代码,使用retry容易产生死循环。
6. else表示没有rescue的时候进行执行else里面的代码。
7. rescue中的代码如下所示,它一般捕获的异常类。
rescue =>e  
#一般是这种形式,如果没有指明是哪个异常类的话,默认是使用StandardError类
#如果按照rescue =>e 这种形式来写的话,如果实际报出的错误不是StandardError类的对象的话,则这个错误捕获不到。
rescue ZeroDivisionError =>e  #也可以表示成这种形式
具体代码如下:
def divide(m)
  begin
    1/m
  rescue ZeroDivisionError => e
    m += 1
    retry
  end
end
divide 0  #=>1

#接上上面的代码继续进行说明,如果  =>e前面没有指明类,默认是StandardError类的对象,但是如果捕获LoadError异常的话,代码报错:
def divide(m)
  begin
    require "xxx"
    1/m
  rescue =>e
    puts "#{e.class}"
  end
end
#执行上面的代码会报错,但是执行下面的代码会出现预期的结果

def divide(m)
  begin
    require "xxx"
    1/m
  rescue LoadError =>e
    puts "#{e.class}"
  end
end

8.rescue可以捕获多个异常,见如下的代码所示:
def divide(m)
  begin
    require "xxx"
    1/m
  rescue LoadError => e
    puts "#{e.class}"
  rescue ZeroDivisionError => e
    puts "#{e.class}"
  end
end
divide(0)  # LoadError

9. rescue的另外一种用法
def divide(m)
  1/m rescue $!
end
divide(0) # ZeroDivisionError: divided by 0

10. ensure不会影响begin的返回值:
def divide(m)
  begin
    1/m
  rescue ZeroDivisionError => e
    puts "#{e.message}"
    m += 1
    retry
  ensure
    puts m*2
  end
end
a = divide 0 
puts a  # =>1,返回值即是begin中的返回值

11. 在ensure中添加return关键词,则影响方法的返回值:
def divide(m)
  begin
    1/m
  rescue ZeroDivisionError => e
    puts "#{e.message}"
    m += 1
    retry
  ensure
    return m*2
  end
end
a = divide 0 
puts a  # =>2,方法的返回值变为return的值

begin
  1/m
rescue =>e
  puts "#{e.message}"
  m += 1
  retry
else
  puts "something"
ensure
  puts "must to do"
end

#如果方法调用的过程中m取值为0,则会报出异常,报出异常的方式其实和raise方法一致:
raise "error A" if m == 0

代码的具体执行步骤如下:
1.create Exception Object
2.set traceback
3.set global exception variable $!

15.require方法

#require方法
如果require的文件不是绝对路径,那么从$LOAD_PATH($:)中寻找相应的文件
可以在终端中执行$LOAD_PATH,查看其中的内容

#relative_require方法
如果要应用相同目录下的文件内容,需要使用relative_require方法
16.respond_to?和respond_to_missing?

reference

#method_missing不友好,它能够代理方法,但是respond_to?的过程中,结果是false:
class Demo
  def method_missing(method, *args, &block)
    if method.to_s =~ /play_(\w+)/
      puts "here is #{$1}"
    else
      super
    end
  end
end

p = Demo.new
p.play_with_girl #=>here is with_girl
p.respond_to? :play_with_girl #=> false

#为了让respond_to?返回true,可以使用下面的语句:
class Demo
  def method_missing(method, *args, &block)
    if method.to_s =~ /play_(\w+)/
      puts "here is #{$1}"
    else
      super
    end
  end

  def respond_to?(method, *)
    method.to_s =~ /play_(\w+)/ || super
  end
end

p = Demo.new
p.play_with_girl #=>here is with_girl
p.respond_to? :play_with_girl #=> 0

#但是其实上面的play_with_girl还是不像一个方法,见如下代码:
p.method :play_with_girl  #=> NameError,undefined method 

#为了解决上面的问题,引入respond_to_missing?方法,下面是完整的解决方案:
class Demo
  def method_missing(method, *args, &block)
    if method.to_s =~ /play_(\w+)/
      puts "here is #{$1}"
    else
      super
    end
  end
  
  def respond_to_missing?(method, *) 
    method =~ /play_(\w+)/ || super 
  end  
end

p = Demo.new
p.play_with_girl #=> here is with_girl
p.respond_to? :play_with_girl #=> true
m = p.method(:play_with_girl)
m.call #=> here is with_girl
m.name #=> play_with_girl
Demo.send :define_method, :hello, m
p.hello #=> here is with_girl
17.define_method
#一般用法:下面的代码直接在类中使用define_method方法定义:test的类
class Test
  define_method :test do
    puts "this is the define_method demo"
  end
end

obj = Test.new
obj.test #=>"this is the define_method demo"

疑惑:为什么可以在类中直接使用define_method方法,以为是实现了module_funciton的功能

module_functon主要实现了下面的两个功能:
1.模块名.方法名直接调用
Kernel.puts "this is the test"
2.类似于关键字在程序的任何部分进行调用
puts "this is the test"
但是,其实在define_method不能实现上面的两个功能

最终解释:
1.define_method是Module类私有实例方法,同时Module类是Class类的父类。
2.define_method做为一般类对象的类方法被直接调用。
#irb: Module.private_instance_method.grep(/define_method/)
#irb: [:define_method]

class Module
  def demo
    puts "this is the demo"
  end

  private :demo
end

class Test
  #对象类中的私有方法,在对象中可以被直接调用,而且必须是隐式调用
  demo
end
18.public方法的调用
1.public的类方法和实例方法可以被显示调用,也可以被隐式调用。
2.这个方法必须在所在的类或者实例化对象的作用域内。

#公开的类方法可以被显示调用,可以被隐式调用:
class DemoClass
  class << self
    def demo_method
      puts "this is the class method"
    end
  end

  DemoClass.demo_method #如期执行
  demo_method #如期执行
end

demo_method #会报undefined method or variable
#上面的方法不在DemoClass这个作用域中,而在Object这个类的作用域中。

#公开的实例方法可以别显示调用,也可以被隐式调用:
class DemoClass
  def demo_method
    puts "this is the instance method"
  end
end

obj = DemoClass.new
obj.demo_method
obj.instance_eval{ demo_method }

19.send方法调用

send是BasicObject类的public instance method,可以被调用的对象包括:
1.普通对象
2.普通类
3.普通模块
4.Kernel模块

class DemoClass
  class << self
    def class_method
      puts "this is the class method"
    end
  end
  def demo_method
    puts "this is the demo"
  end
end

obj = DemoClass.new
obj.demo_method
obj.send(:demo_method) #可以被普通对象调用
Kernel.send(:puts, "cc") #可以被Kernel模块调用
DemoClass.send(:class_method) #可以被普通类调用

module Mod
  class << self
    def module_method
      puts "this is the module method"
    end
  end
end

Mod.send(:module_method) #可以被普通模块进行定义

#send方法可以被普通对象调用
DemoClass.superclass #=> Object
Object.superclass #=>BasicObject
#类DemoClass间接继承于BasicObject类,继承send方,DemoClass的普通对象可以调用BasicObject类的实例方法send。

#send方法可以被普通类进行调用
DemoClass.class #=>Class
Class.superclass #=>Object
#send方法是Class类的实例化方法,亦是DemoClass类的类方法。

#send方法可以被普模块调用
Mod.class #=>Module
Module.superclass #=>Object
#send方法是Module类的实例方法,是其实例化对象即普通模块的模块方法。

#send方法可以被Kernel模块调用
#Kernel模块是Module类的一个普通实例化对象,代码如下所示:
Kernel.class #=>Module
20.模块和类的区别
1.在类中,类的实例方法是其类对象的类方法。
2.因为类和模块相比,只是增加了三个方法(new, allocate,superclass)

#类的形式
class String
  def self.inherited(subclass)
    puts "#{self} was inherited by #{subclass}"
  end
end

class MyClass < String; end  #=> String was inherited by MyClass

#inherited是Class类的私有实例方法:
Class.private_instance_methods.grep(/inherited/)  #=>[:inherited]
#String是Class的实例化对象,因此Class的实例方法也就成了String类(本质上是一个对象)的类方法。

#模块的形式
module M; end
M.class #=>Module

module M
  def self.incluede(othermod)
    puts "M was mixed into #{othermod}"
  end

  class C
    include M
  end
end

#include方法是类Module的私有实例方法:
Module.private_instance_methods.grep(/include/) #=>[:include]
#普通的模块其实是类module的对象,因此moudle类的实例方法是其实例化对象(也就是一个普通模块)的模块方法

所以,类和模块在原理上其实是一致的。

21.计算行数中的闭包问题

闭包:是引用了一个作用域外的变量并且可以被调用的函数。

ltotal = 0

ARGV.each do |file| 
  begin 
    input = File.open(file)
    l = 0 
    input.each_line do |line| 
      l += 1 
      #ltotal += l #最终执行结果为153 
      #检测这个问题的方法是将如下的结果在控制台打印出来
      #puts l
      #puts ltotal
    end 
    input.close 
    ltotal += l #最终执行结果为17 
  rescue =>e 
    puts "#{e.message}" 
  end
end

puts ltotal

22.表达式的求值顺序

1.解释器对每个表达式都是从右向左求值的
2.同一个作用域的方法才能调用,不同作用域的方法不能调用
3.send方法接受返回字符串对象和符号对象的方法名的方法也是可以的。

1.解释器对每个表达式都是从右向左求值的
class Computer
  def mouse
    component :mouse
  end
  
  def component(name)
    puts "get the #{name} information in the computer"
  end
end

cp = Computer.new
cp.mouse

#返回预期的结果:
def mouse
  component :mouse
end

#更改代码
def mouse
  component(mouse) #出现SystemStackError错误
end

#解释器对每个表达式都是从右向左求值的的
def mouse
  component :mouse#将:mouse理解为符号对象
end

#更改代码
 def mouse
   component(mouse) #将mouse理解为方法,因此出现如上死循环错误
 end

#出现如下的错误
component(mouse)
component(component(mouse))
component(component(component(mouse)))

#改动代码
 def mouse
   component cc #undefined local variable or method "cc"
 end
#解释:解释器对表达式是从右向左求值,但是cc这个变量没有被定义过,按照这个形式,有可能是方法,也有可能是局部变量。

2.同一个作用域的方法才能调用,不同作用域的方法不能调用
class MyClass 
  def my_method(my_arg) 
    puts my_arg*2 
  end
end
obj = MyClass.new
obj.send(:my_method, 3) #=>6
obj.send("my_method", 6) #=>6
obj.send(my_method, 6) #=> undefined variable or method error

#调用方法需要考虑作用域的
class Computer 
  def mouse
    component mouse 
  end 

  def component(name) 
    puts "get the #{name} information in the computer" 
  end
end
#component方法调用mouse方法,这两个方法在同一个作用域中

#调用my_method方法的时候,会在该方法的作用域中寻找该方法,但是my_method方法跳出MyClass之后,就失效了,该方法的作用域是顶级作用域
#区别obj.send(my_method)和obj.my_method
obj.send(my_method, 6) #=> undefined variable or method error

3.send方法接受返回字符串对象和符号对象的方法名
class MyClass 
  def my_method(my_arg) 
    puts my_arg*2 
  end
end
obj = MyClass.new

def simulate
  :my_method
end

obj.send(simulate, 6) #=>6

23.case用法

#第一种情况类似于if语句
year=2012
leap = case
  when year%400 == 0 then true
  when year%100 == 0 then false
  else year%4 == 0
end
puts leap

#第二种情况case语句的顶部指定一个目标,而每个when从句列出一个或者多个比较条件
input="run"
case input
  when "debug"
    print "debug time"
  when "run"
    print "run now"
  else
    print "wrong"
end

24.map和each的返回值
需要取出tag数组中的name值,并且作为字符串显示,两个方法都是进行遍历,但是each返回的还是原来的数组,map返回的是遍历后的数组,所有后者能达到所要的效果,两个方法都不能改变数组本身。

#map
a=[[1,"a"], [2,"b"]]
a.each(&:first).join(",") #=>[[1,"a"], [2,"b"]]
b.each(&:first).join(",") #=>"1,2"

25.赋值和拷贝
赋值是创建一个引用,如果将一个对象赋值给另外一个对象,那么这两个对象指向同一个引用:

str1 = 'hello' # => "hello"
str1.object_id # => 17940720
str2 = str1 # => "hello"
str2.object_id # => 17940720

两个对象均指向同一个引用,如图所示:

两个对象均指向同一个引用

如果修改其中一个对象,则会改变其引用,也即是改变另外一个对象。但是还是指向的是同一个引用。

str2 << '!' # => "hello!"
str1 # => "hello!"
str2 # => "hello!"

str1.object_id #=>70296829690720
str2.object_id #=>70296829690720

如果对其中一个对象重新复制,则两个对象不再指向同一个引用。

str2 = 'ruby!' # => "ruby!"
str2.object_id # => 17304640
str1.object_id # => 17940720
对象被重新赋值之后不再指向同一引用

http://www.tuicool.com/articles/2q2eA3Y

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,636评论 0 9
  • //Clojure入门教程: Clojure – Functional Programming for the J...
    葡萄喃喃呓语阅读 3,508评论 0 7
  • 她是合肥四大家族的千金,嫁给仅次于蒋介石的男人,一生悲苦 1990年10月11日,孙立人住进了医院, 在接下来一个...
    徽脸老史阅读 1,767评论 0 0
  • 此生多槛折 所幸红尘多沉浮 无谓刀剑水火 意欲与之同守 时有清风入户 开轩琴瑟共和 可举玉樽共酌 泠泠清韵入耳 可...
    一纸相思万卷愁阅读 325评论 0 3