代码之家  ›  专栏  ›  技术社区  ›  c4757p

Ruby模块中的私有类(不是类方法)?

  •  16
  • c4757p  · 技术社区  · 14 年前

    我是Ruby的新手(对Python、C++和C有经验)。我需要创建一个类,该类只供模块中的其他类和方法使用。在python中,我称之为uuclassname。我将在C++中使用一个空的Type。我该如何在Ruby中做到这一点(或者我是在错误的树上狂吠而不是用“Ruby的方式”?)

    3 回复  |  直到 8 年前
        1
  •  4
  •   Mladen Jablanović    14 年前

    到目前为止,我在Ruby中还没有看到这样的概念,但我想您可以通过创建私有方法来模拟,该方法将返回一个创建为局部变量的类(记住,在Ruby中,类与其他任何类一样是一个对象,可以在一个方法中实例化并由它返回)。

    顺便说一句,即使Ruby中的私有方法也不像其他语言中的私有方法那样-您可以使用 send 方法。但是这样做意味着你知道你在做什么。

        2
  •  27
  •   Jörg W Mittag    14 年前

    最重要的是要认识到一个班级并不是什么特别的。它只是一个物体。按照惯例,类被分配给常量,但没有任何内容说明它们 成为。

    由于类和其他对象一样只是对象,所以您可以像使其他对象私有一样使它们私有。

    以下是我能想到的可能性,按照私密性增加的顺序:

    1. 只需将它们嵌套在名称空间(即模块)中即可。在Ruby中,通常期望库中的所有模块和类都位于与库同名的名称空间中(即 my_awesome_library 渐次 MyAwesomeLibrary ,但一般来说,嵌套在该命名空间下面的所有内容都被视为私有的。事实上,还有 Test::Unit::TestCase ,我想不出一个三层深度的命名空间的例子,它实际上被客户机代码所使用。
    2. 与1.相同,但要把它命名为一些明显的东西,比如 MyAwesomeLibrary::Internal::FfiStruct
    3. 和1一样。或2.并用 :nodoc: RDOC标签。
    4. 类似于3.,但是使用一个更现代的文档系统,比如yard,它实际上允许您显式地标记私有API。
    5. 使用方法而不是常量。方法可以设置为私有。(为了一致性起见,可以让方法名以大写字母开头,使其类似于常量。没有什么可以阻止的, snake_case 约定就是这样:约定。)
    6. 使用实例变量。它们总是私人的。请注意,私有方法和实例变量都可以使用反射进行琐碎的访问。 send 似乎比 instance_variable_get 不过,这也是为什么我认为实例变量比方法具有更高的隐私级别的原因。
    7. 实际上,获得实际隐私或封装的唯一方法是使用局部变量和闭包。但是请注意,这可能会阻止您使用Ruby的模块、类或方法定义语法,因为这些语法创建了新的范围。在所有需要访问类的情况下,都需要使用 Module.new , Class.new Module#define_method .

    前任。:

    module MyAwesomeLibrary
      struct = Class.new(FFI::Struct) do
        # ...
      end
    
      PublicInterface = Class.new do
        define_method(:initialize) do |bar|
          @foo = struct.new(bar)
        end
      end
    end
    

    是的,这是 只有 在Ruby中实现真正100%信息隐藏和封装的方法。

    然而,通常的Ruby方法是简单地将这些东西记录为私有的(可能会将其向下推到一个名称空间级别),并信任您的开发伙伴。在Ruby社区,这有时被总结为python的口号“我们都是同意的成年人”。

        3
  •  10
  •   aceofbassgreg    8 年前

    直接从 this blog post ,但是由于Ruby1.9.3,您可以使用 private_constant :

    class Person
      class Secret
        def to_s
          "1234vW74X&"
        end
      end
      private_constant :Secret
    
      def show_secret
        Secret.new.to_s
      end
    end