1

调用初始化方法时出现错误:

# typed: true
class A
  extend T::Sig

  sig {params(x: Integer).void}
  private def initialize(x)
  end
end

def main
  A.new(91)  
end

这是冰糕的结果:

editor.rb:11: Non-private call to private method initialize on A https://srb.help/7031
11 |  A.new(91)  
      ^^^^^^^^^
editor.rb:6: Defined in A here
 6 |  private def initialize(x)
              ^^^^^^^^^^^^^^^^^
Errors: 1

https://sorbet.run/#%23%20typed%3A%20true%0Aclass%20A%0A%20%20extend%20T%3A%3ASig%[…]0A%20%20end%0Aend%0A%0Adef%20main %0A%20%20A.new(91)%20%20%0结束

4

1 回答 1

3

这看起来像是 Sorbet 中的一个错误,因为initialize语言对其进行了特殊处理,因此无论如何总是 private默认的。换句话说,您的代码与相同的代码100%相同,但没有private

# typed: true
class A
  extend T::Sig

  sig {params(x: Integer).void}
  def initialize(x)
  end
end

def main
  A.new(91)  
end

p A.private_instance_methods(false).include?(:initialize)
#=> true

它通过了出色的类型检查。

我的猜测是 Sorbet 并不“知道” initializeRuby 中对 的特殊处理,因此将其视为正常方法。我的第二个猜测是 Sorbet 包含一个Class#new如下所示的定义:

class Class
  def new(...)
    obj = allocate
    obj.initialize(...)
    obj
  end
end

这意味着只要 Sorbet认为 initializepublic,一切都是 honky-dory,但一旦它认为private,它就失败了。

然而,实际的实现Class#new看起来更像这样:

class Class
  def new(...)
    obj = allocate
    obj.__send__(:initialize, ...)
    obj
  end
end

如果我的假设是正确的,那么 Sorbet 中有两个错误通常会相互抵消:

  • 的定义Class#new是错误的。这意味着你总是会得到一个错误,因为initializeis always private,除了
  • 的默认可见性initialize也是错误的。

但是,我没有检查这些假设,所以我可能会完全放弃。

于 2020-12-22T13:36:07.183 回答