美文网首页
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