Ruby中的静态块

Pri*_*ank 4 ruby constructor

我有一段时间以来一直是Java程序员,我试图转换为ruby一段时间.我只是想在ruby中开发一个小测试程序,我的意图就像是跟随.

  1. 我想在ruby中创建一个简单的链接列表类型的对象; 其中类中的实例变量指向另一个相同类型的实例.
  2. 我想填充并链接所有节点; 在构造函数被调用之前只有一次.我们通常在Java Static块中做的事情.

  3. Initialize方法是ruby中的构造函数签名.他们周围有什么规则吗?就像在Java中一样,如果它不是第一行(或者在调用类代码之后?),你就不能从构造函数中调用另一个构造函数.

谢谢您的帮助.-Priyank

Jör*_*tag 19

我想在ruby中创建一个简单的链接列表类型的对象; 其中类中的实例变量指向另一个相同类型的实例.

简单说一句:单词类型在Ruby中是一个非常危险的词,特别是如果你来自Java.由于历史性事故,这个词在动态打字和静态打字中都被用来表示两个表面上相关但非常不同的东西.

在动态类型中,类型是附加到(而不是引用)的标签.

此外,在Ruby中,类型的概念比Java更广泛.在Java程序员的脑海中,"类型"意味着与"类"相同(尽管事实并非如此,因为接口和基元也是类型).在Ruby中,"类型"意味着"我能用它做什么".

示例:在Java中,当我说某些类型为String时,我的意思是它是类的直接实例String.在Ruby中,当我说某些类型为String时,我的意思是它

  • 类的直接实例String
  • 类的子类的实例String
  • 响应#to_str方法或对象的对象
  • 一个与String无法区分的对象.

我想填充并链接所有节点; 在构造函数被调用之前只有一次.我们通常在Java Static块中做的事情.

在Ruby中,一切都是可执行的.特别是,没有"类声明"这样的东西:类主体只是可执行代码,就像任何其他代码一样.如果您的类主体中有方法定义列表,那么这些不是由编译器读取然后转换为类对象的声明.这些是由评估者逐个执行的表达式.

因此,您可以将任何您喜欢的代码放入类主体中,并在创建类时对该代码进行评估.在类体的上下文中,self绑定到类(请记住,类只是与其他类似的对象).

Initialize方法是ruby中的构造函数签名.他们周围有什么规则吗?就像在Java中一样,如果它不是第一行(或者在调用类代码之后?),你就不能从构造函数中调用另一个构造函数.

Ruby没有拥有构造函数.构造函数只是工厂方法(有愚蠢的限制); 没有理由让它们采用精心设计的语言,如果你可以使用(更强大的)工厂方法.

Ruby中的对象构造如下:对象构造分为两个阶段,分配初始化.分配由一个名为的公共类方法完成,该方法allocate被定义为类的实例方法,Class通常不会被覆盖.它只是为对象分配内存空间并设置几个指针,但是,此时该对象并不真正可用.

这就是初始化程序的用武之地:它是一个名为的实例方法initialize,它设置对象的内部状态并将其置于一个完全定义的一致状态,可供其他对象使用.

所以,为了完全创建一个新对象,你需要做的是:

x = X.allocate
x.initialize
Run Code Online (Sandbox Code Playgroud)

[注意:Objective-C程序员可能会认识到这一点.]

但是,因为它太容易忘记调用,initialize并且作为一般规则,对象在构造之后应该是完全有效的,所以有一个方便的工厂方法调用Class#new,它可以为你完成所有工作,看起来像这样:

class Class
  def new(*args, &block)
    obj = alloc
    obj.initialize(*args, &block)

    return obj
  end
end
Run Code Online (Sandbox Code Playgroud)

[注意:实际上,它initialize是私有的,因此必须使用反射来规避这样的访问限制:obj.send(:initialize, *args, &block)]

顺便说一下,这就是构造一个你调用公共类方法的对象的原因,Foo.new但是你实现了一个私有实例方法Foo#initialize,这似乎让许多新手绊倒了.

回答你的问题:由于初始化方法只是一种与其他方法一样的方法,因此对于你在初始化器中可以做什么没有任何限制,特别是你可以super随时随地,无论何时以及多少次调用.

BTW:因为initializenew只是正常的方法外,还有就是为什么他们需要被调用没有理由initializenew.这只是一个惯例,虽然它非常强大,因为它体现在核心库中.在您的情况下,您想要编写一个集合类,并且集合类提供一个名为的替代工厂方法是非常习惯的[],因此我可以调用List[1, 2, 3]而不是List.new(1, 2, 3).

正如旁注:使用常规方法构造对象的一个​​明显优势是可以构造匿名类的实例.这在Java中是不可能的,因为绝对没有任何明智的理由.它不起作用的唯一原因是构造函数与类具有相同的名称,而匿名类没有名称,因此不能有构造函数.

虽然我不太确定为什么在创建对象之前需要运行任何东西.除非我遗漏了什么,否则基本上不应该列出

class List
  def initialize(head=nil, *tail)
    @head = head
    @tail = List.new(*tail) unless tail.empty?
  end
end
Run Code Online (Sandbox Code Playgroud)

对于Lisp风格的缺点或

class List
  def initialize(*elems)
    elems.map! {|el| Element.new(el)}
    elems.zip(elems.drop(1)) {|prv, nxt| prv.instance_variable_set(:@next, nxt)}
    @head = elems.first
  end

  class Element
    def initialize(this)
      @this = this
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

一个简单的链表?