【问题标题】:Examine method metadata (i.e. arity, arg types, etc)检查方法元数据(即 arity、arg 类型等)
【发布时间】:2018-09-05 14:21:14
【问题描述】:

在 Crystal 中,是否可以在编译时查看类型方法的元数据?例如,要确定方法接受的参数数量、参数的类型限制是什么等。

查看 API,编译器的 DefArg 宏具有据称返回此元信息的方法,但我看不到访问它们的方法。我怀疑元信息只能由编译器访问。

【问题讨论】:

    标签: crystal-lang


    【解决方案1】:

    我知道怎么做。我在寻找 API 的错误位置。 Crystal::Macros::TypeNode 有一个 methods 宏,它返回一个方法数组 Def (这是您可以访问它们的方式)。看起来TypeNode 类是许多优秀宏的入口点。

    使用示例

    class Person
      def name(a)
        "John"
      end
    
      def test
        {{@type.methods.map(&.name).join(', ')}}
      end
    end
    

    或者

    {{@type.methods.first.args.first.name}}
    

    简单地返回参数名称存在一个有趣的问题,因为在宏解释器将其粘贴到程序中之后,编译器将名称解释为变量(这是有道理的)。

    但是真正的值发生在能够看到方法参数的类型限制

    class Public < Person
      def name(a : String)
        a
      end
    
      def max
        {{@type.methods.first.args.first.restriction}}
      end
    end
    
    Person.new.max # => String
    

    【讨论】:

    • 太好了,如果这符合您的要求。但请注意,这不是运行时反射。宏在编译时被扩展,所以你可以通过你的宏从TypeNode 得到的所有东西都在那个时候固定。
    • 话虽如此,我非常感谢您的回复。
    • 对不起,但第一句话要求“在运行时查看对象方法的元数据”。这明确描述了运行时反射。您的答案没有提供这一点,因为您不能只向对象询问其方法名称。
    • @JohannesMüller 知道我的目标是什么,你会如何表达这个问题?
    • 也许不要求对象的运行时信息,而是类型的编译时间信息?
    【解决方案2】:

    我怀疑元信息只能由编译器访问。

    没错。 Crystal 没有运行时反射。您可以在编译时使用宏做很多事情,但是一旦编译,类型和方法信息就不再可用。

    但是,由于程序中的所有内容都已知为编译时间,因此您实际上不需要运行时反射。

    【讨论】:

    • 这是不正确的。事实证明,您可以通过 TypeNode 访问类上的方法。另外,我对~“因为程序是编译的,你不应该需要运行时反射。”从技术上讲,我什至需要在语言中乘以数字的能力。我可以坚持加法(一次又一次地添加东西)。或者在这个问题的情况下,我可以使用另一种语言来分析我的水晶源,获取方法列表,然后将它们复制粘贴到水晶程序中。但幸运的是,水晶人让我使用TypeNode 访问这些方法。
    • 我的说法确实有效。但是,当您实际上只关心编译时反射时,您似乎问错了问题(运行时反射)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    • 2016-08-18
    • 2015-03-18
    • 2022-10-12
    相关资源
    最近更新 更多