最近在学习ruby的过程遇到很多有趣的博客,随记录学习,这篇学习笔记摘自http://yugui.jp/articles/846

#self

ruby中self无处不在,或是显示的调用或是隐含调用,方法调用如果不指明接收者,那么默认也是self。打开pry

ruby --version => ruby 2.4.0p0
p self                      => main

class Persion
p self => Persion
def hello(param = (p self));end
end Persion.new.hello => #<Persion:0x007ff03d3b5468> class Manager
class Employ < (p self; self) => Manager
end
end

#default definee

ruby 中默认存在一个指向 class 的引用,不像 self可以随处调用,这个引用比 self 更加隐含,暂且称之为 default definee, 如果方法定义时不提供默认的接受者,那么方法默认就会作为 default definee 的实例方法,代开pry

def hello;end
Object.instance_method(:hello) => #<UnboundMethod: Object#hello> class Persion
def hello;end
end Persion.instance_method(:hello) => #<UnboundMethod: Persion#hello>

在正常的方法体内(def 定义的方法), self 是方法的接受者,但是内部函数的 default deinee 却是外层的class,例如:

class Persion
def hello
def speak;end
end
end p = Persion.new
p.hello
p.method(:hello) => #<Method: Persion#hello>
Persion.instance_method(:speak) => #<UnboundMethod: Persion#speak>

如果方法内部想要定义实例方法可以用self,本质上方法会被添加到对象的单例类上

class Persion
def hello
def self.speak;end
end
end p = Persion.new
p.hello
p.method(:hello) => #<Method: Persion#hello>
p.method(:speak) => #<Method: #<Persion:0x007fc5fe1cfe00>.speak>
p.singleton_class.instance_method(:speak) => #<UnboundMethod: #<Class:#<Persion:0x007fc5fe1cfe00>>#speak>

正常方法体内的 default definee 都是外层的class

class Manager;end

$m = Manager.new => #<Manager:0x007f890e474958>
class Employee
def $m.hello(param = (def speak;end))
def sing;end
end
end $m.hello
Employee.instance_method(:speak) => #<UnboundMethod: Employee#speak>
Employee.instance_method(:sing) => #<UnboundMethod: Employee#sing>
$m.method(:speak) => NameError: undefined method `speak' for class `#<Class:#<Manager:0x007f890e474958>>'

# eval

# instance_eval

instacne_eval 会执行以下操作:

  • 修改 self 为 instance_eval 的接受者
  • 修改 default definee 为 instance_eval 的单例类
o = Object.new
o.instance_eval do
p self
def hello; end
end o.method(:hello) => #<Method: #<Object:0x007f890ec8e698>.hello>
o.singleton_class.instance_method(:hello) => #<UnboundMethod: #<Class:#<Object:0x007f890ec8e698>>#hello>

下一个例子

class Persion
$o = Object.new $o.instance_eval do
def hello(param = (def speak;end))
def sing;end
end
end
end $o.hello
$o.method(:speak) => #<Method: #<Object:0x007fee5f3f4b98>.speak>
$o.method(:sing) => #<Method: #<Object:0x007fee5f3f4b98>.sing>
Persion.instance_method(:hello) => NameError: undefined method `hello' for class `Persion'
Persion.instance_method(:speak) => NameError: undefined method `speak' for class `Persion'
Persion.instance_method(:sing) =>NameError: undefined method `sing' for class `Persion'
$o.singleton_class.instance_method(:hello) => #<UnboundMethod: #<Class:#<Object:0x007fee5f3f4b98>>#hello>
$o.singleton_class.instance_method(:speak) => #<UnboundMethod: #<Class:#<Object:0x007fee5f3f4b98>>#speak>
$o.singleton_class.instance_method(:sing) => #<UnboundMethod: #<Class:#<Object:0x007fee5f3f4b98>>#sing>

# class_eval

class_eval 会把 self 和 default definee 都修改为class_eval 的接受者

class Persion;end

Persion.class_eval do
p self => Persion
def hello; end
end Persion.new.method(:hello) => #<Method: Persion#hello>
Persion.instance_method(:hello) => #<UnboundMethod: Persion#hello>

明白了以上几点,那么下面这个例子就很好理解了:

Persion.instance_eval { define_method(:hello) { "hello" } }

Persion.class_eval { define_method(:sing) { "sing" } }

Persion.instance_eval { def speak; 'speak'; end }

Persion.class_eval { def dance; 'dance'; end }

p Persion.new.hello => "hello"
p Persion.new.sing => "sing"
p Persion.speak. => "speak"
p Persion.new.dance => "dance"

self_vs_default_definee_vs_receiver的更多相关文章

随机推荐

  1. Android studio下载慢解决,使用阿里云解决(转)

    转自:https://blog.csdn.net/kangweijian/article/details/79120849?%3E 使用开源中国的maven库 阿里云的(速度飞快):http://ma ...

  2. python day06笔记总结

    2019.4.3 S21 day06笔记总结 一.昨日内容补充 1.列表独有功能: 1.revers 反转 例:v1 = [1,2,4,88,2] v1.revers() print(v1) 2.so ...

  3. 云笔记项目- 上传文件报错"java.lang.IllegalStateException: File has been moved - cannot be read again"

    在做文件上传时,当写入上传的文件到文件时,会报错“java.lang.IllegalStateException: File has been moved - cannot be read again ...

  4. Redis主从集群及哨兵模式

    本次实验环境准备用一台服务器模拟3台redis服务器,1主2从 主从集群搭建 第一步:安装Redis 安装Redis,参考前面安装Redis文章,保证单机使用没有问题. 第二步:配置服务器文件 定位到 ...

  5. [Solution] 985. Sum of Even Numbers After Queries

    Difficulty: Easy Question We have an array A of integers, and an array queries of queries. For the i ...

  6. 【Spring源码解析】—— 依赖注入结合SpringMVC Demo-xml配置理解

    在IOC容器初始化的梳理之后,对依赖注入做一个总结,就是bean实例化的过程,bean的定义有两种方式,一种是xml文件配置,一种是注解,这里是对xml配置文件的依赖注入的介绍,后续对bean与该部分 ...

  7. 【noip模拟赛5】细菌 状压dp

    [noip模拟赛5]细菌   描述 近期,农场出现了D(1<=D<=15)种细菌.John要从他的 N(1<=N<=1,000)头奶牛中尽可能多地选些产奶.但是如果选中的奶牛携 ...

  8. mysql系列博客

    近期,打算开始我的sql之路了,计划写一些sql方面的博客,初步定的计划,先写mysql,如果有必要,再写oracle.mysql如下: 1.mysql的调优思路 2.mysql 的执行过程 http ...

  9. 分析easyswoole3.0源码,服务启动为例(一)

    swoole已经升级到4了,主要的特性是更好的支持协程,easyswoole也为了更好支持协程推出了es3.我本地环境是php7.2.9 centos7 在github下载最新的3.0的demo.地址 ...

  10. Matting任务里的Gradient与Connectivity指标

    Matting任务里的Gradient与Connectivity指标 主要背景 Matting任务就是把α(不透明度, 也就是像素属于前景的概率).F(前景色)和B(背景色)三个变量给解出来. C为图 ...