美文网首页
basic code

basic code

作者: littleyu | 来源:发表于2020-09-06 16:31 被阅读0次

一个简单的测试

// gem install test-unit --verbose
def to_word(s)
  s.gsub(/\d/, '')
end

require 'test/unit'

class ToWordTest < Test::Unit::TestCase
  def test1
    assert_equal 'hello world', to_word('234234he345345l345345lo345345 wo345r4353ld')
  end
end

在 class String 上添加方法

class String
  def to_word
    self.gsub(/\d/, '') # self 可以省略
  end
end

require 'test/unit'

class ToWordTest < Test::Unit::TestCase
  def test1
    assert_equal 'hello world', '234234he345345l345345lo345345 wo345r4353ld'.to_word
  end
end

Class

重复的 class

3.times do
  class C
    p 'hello'
  end
end

验证只是 class 可以重复声明且会自动合并

class C
  def x
    p 'x'
  end
end

class C
  def y
    p 'y'
  end
end

z = C.new
z.x
z.y

自定义一个 class

class MyClass
  def initialize
    @v = 1
  end
  def add
    @v += 1
  end
end

obj = MyClass.new

p obj.class
p obj.add
p obj.instance_variables
p MyClass.instance_variables
p obj.methods
p MyClass.instance_methods
p obj.methods.grep(/add/)

证明,一个对象的实例变量储存在自身,一个对象的实例方法存储在其类身上

superclass (类似于 JS 的原型链)

p '----String----'
p String.superclass # Object
p Object.superclass # BasicObject
p BasicObject.superclass # nil

p String.is_a? Class

p '----Array----'
p Array.superclass # Object
p Array.is_a? Class

class MyClass; end
p MyClass.superclass # Object
p MyClass.is_a? Class

p 'class is a Class?'
p Class.is_a? Class

p Class.superclass # Module
# 模块是低配版的类,类是高配版的模块

模块是低配版的类,类是高配版的模块

常量

Const1 = 'root const'
module MyModule
  Const1 = 'outer const'
  class MyClass
    Const1 = 'inner const'
    p ::Const1 # 'root const'
  end
end

p Const1 # 'root const'
p MyModule::Const1 # 'outer const'
p MyModule::MyClass::Const1 # 'inner const'

使用 :: 打印出内部的常量,直接使用 :: 可以打印出根的常量

p '------------'
p MyModule.constants

使用 MyModule.constants 得到 MyModule 的内部的所有一级常量

Const1 = 'root const'
module MyModule
  Const1 = 'outer const'
  class MyClass
    Const1 = 'inner const'
    p 'Module.nesting'
    p Module.nesting # [MyModule::MyClass, MyModule]
  end
end

使用 Module.nesting 得到 当前作用域的层级结构

祖先链

class MyClass
  def my_class
    'my_class'
  end
end

class MySubClass < MyClass # < 表示继承

end

obj = MySubClass.new

p obj.my_class
p MySubClass.ancestors # [MySubClass, MyClass, Object, Kernel, BasicObject] # 其中 Kernel 是祖先模块

module

模块和类非常非常像,只是模块不能继承

module M1
  def my_methods
    'M1#my_methods'
  end
end

class C1
  include M1
end

class A1 < C1

end

p A1.ancestors # [A1, C1, M1, Object, Kernel, BasicObject]
module M1
  def my_methods
    'M1#my_methods'
  end
end

class C1
  prepend M1
end

class A1 < C1

end

p A1.ancestors # [A1, M1, C1, Object, Kernel, BasicObject]

使用 include (上面增加)和 prepend(下面增加)
可以在类中引入模块,用来改变方法查找顺序,使得继承组合更加多样化

self (method 的查找方法)

self 是当前对象

class MyClass
  def test_self
    @var = 10
    me_method
    self
  end
  def me_method
    @var += 1
  end
end

obj = MyClass.new
p obj.test_self # #<MyClass:0x00000000051488b8 @var=11>

可以看到 @var 已经是 11 了,执行顺序:先找 obj 上的 test_self, 在MyClass 上找到,执行该方法,该方法声明了 @var 并执行 me_method 方法,注意调用该方法时,self已经变了,所以 me_method 才能给 @var 加一

特殊:顶级的 self

p self # main

p 出来的肯定是对象,为什么是 main,只需要改写其 to_s 和 inspect 方法即可,

o1 = {name: 'zch'}
p o1
p self
class Temp
  def to_s
    'temp'
  end

  def inspect
    'temp'
  end
end
p Temp.new

self 也可以是类

class MyClass2
  p 'MyClass2'
  p self # self 是类
  def my_method
    p self
  end
end

私有方法

class MyClass
  def public_method
    'MyClass::public_method'
  end
  private
  def private_method1
    'MyClass::private_method1'
  end
  def private_method2
    'MyClass::private_method2'
  end
end

使用 private 分隔私有方法,非常机智,private 以上都是不是私有的,下面都是私有的

obj = MyClass.new
obj.public_method
obj.private_methods1 # 报错
obj.private_methods2 # 报错

调用 private 方法

class MyClass
  def public_method1
    self.private_method1 # 报错
  end
  def public_method2
    private_method1
  end
  private
  def private_method1
    'MyClass::private_method1'
  end
  def private_method2
    'MyClass::private_method2'
  end
end

私有方法调用必须满足如下情况

  1. 必须在对象所在的类中调用
  2. 不能再前面加 self 字样(只能隐式指定 self)

动态调用方法

调用方法有两种

  1. obj.xx_method('hi')
  2. obj.send(:xx_method, 'hi')
class Notification
  def notify(witch)
    send "notify_#{witch}"
  end
  private
  def notify_wx
    p '通知到威信'
  end
  def notify_qq
    p '通知到qq'
  end
  def notify_phone
    p '通知到手机'
  end
  def notify_all
    notify_wx
    notify_qq
    notify_phone
  end
end

obj = Notification.new
obj.notify('qq')

注意 send 调用方法不分共、私有,上述可以直接 obj.send(:notify_qq, 'hi')

动态定义方法

class MyClass
  x = :methods1
  define_method x do |n|
    n * 3
  end
end

require 'test/unit'
class MyClassTest < Test::Unit::TestCase
  def test_1
    obj = MyClass.new
    assert_equal 6, obj.methods1(2)
  end
end

动态定义的好处:可以在运行时决定方法的名字,而不是写代码时
这在批量创建方法时非常有用

自定义未定义方法(狗头)

class MyClass;end
obj = MyClass.new
obj.xxx

调用 obj.xxx, 一般来说调用一个未定义的方法,其他语言会直接报错,但是 ruby 不会,obj 会一直向上查找,直到调用 BaseObject#method_missing 这个方法去报错
也就等同于 obj.send(:method_missing, :xxx) ,这两个报错一模一样,即可验证

所以我们就可以直接覆盖 method_mssing

class MyClass
  private def method_missing(method, *args)
    p "method:#{method},参数:#{args}"
    p '找不到方法啊,大哥'
  end
end

obj = MyClass.new

obj.xxx(1,2,3)

这么做以后,就可以让一个对象响应任何一个方法

相关文章

网友评论

      本文标题:basic code

      本文链接:https://www.haomeiwen.com/subject/yztfektx.html