最近在学习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. Halcon知识点随记(每日更新)

    部分积累自重码网视频 1.dev_update_off.dev_update_on 一般dev_update_off放在开始,dev_update_on放在程序结束 dev_update_window ...

  2. jmeter学习笔记--概述

    jmeter:概述 是什么? jmeter是Apache 公司使用java开发的一款测试工具 为什么? 高效.功能强大 模拟一些高并发或多次循环等特殊场景 怎么用? 1.下载jmeter,解压缩 2. ...

  3. springboot+dubbo+mybatis多模块项目invalid boundexception

    invalid boundexception的原因大抵是因为mybatis扫描不到mapper映射文件(xml),无法将mapper接口类(java)中的接口与mapper映射器绑定起来.这可能是因为 ...

  4. PowerScript表达式

    运算符 算术运算符 双目运算符 运算符 名称 示例 说明 ^ 乘方 3^2   + 加 i_age+1   - 减 i_age - 1   * 乘 l_w*3   / 除 i_w/3   = 赋值 i ...

  5. TZOJ 5694 区间和II(树状数组区间加区间和)

    描述 给定n个整数,有两个操作: (1)给某个区间中的每个数增加一个值: (2)查询某个区间的和. 输入 第一行包括两个正整数n和q(1<=n, q<=100000),分别为序列的长度和操 ...

  6. php下kafka实践

    Kafka是一种高吞吐的分布式发布订阅消息系统 kafka安装和简单测试 安装kafka 下载 wget https://www-us.apache.org/dist/kafka/2.1.1/kafk ...

  7. @Autowired注解和静态方法

    @Autowired注解入static属性时,出现NullPointerException异常. 使用构造方法可解决: @Component public class Test { private s ...

  8. $.ajax()参数详解

    来自于<锋利的jQuery(第2版)>. 参数 类型 说明 accepts Map 内容类型发送请求头,告诉服务器什么样的响应会接受返回. 如果accepts设置需要修改,推荐在$.aja ...

  9. Linux 学习笔记 2:文件系统

    1.文件系统层次结构 系统目录内容: /: 根目录(之后的/都是目录分隔符) /home:用户目录 /bin: Unix常用命令,如bash, date, cat, tar等 /sbin: 管理员命令 ...

  10. js处理日期

    /Date(-62135596800000)/ 如何用js转化为日期时间格式 2015-11-20 14:33:20像这样 var a = '/Date(-62135596800000)/' Date ...