首页 文章

crystal lang:在一个类作为场的情况下

提问于
浏览
3

我只是在编写一个Exception,它应该将 Class 对象存储为错误消息进程的字段 .

class BadType < Exception
    getter should_be : Class
    getter actual : Class
end
def feed(pet : Animal, food : Food)
    raise BadType.new should_be: Cat, actual: pet.class if food == "fish" && !pet.is_a?(Cat)
end

但是, Class 是抽象的,所以不能在这里用作字段类型 .

那么,在我的案例中如何解决这个问题呢?我没有找到 Class 的任何派生类,所以它是否意味着永远不能将 Class 对象存储为字段?但在这里我的问题是一个有意义的用法(任何类型检查取决于输入可能需要这 BadType ) .

我不确定我是否错过了什么,所以我先来到这里 .

2 回答

  • 4

    Class 可以't (yet) be used as a ivar type. Maybe it never will, I don'知道 .

    但实际上,您可以将泛型用于具体数据类型,从构造函数的参数推断:

    # possible workaround
    class Foo(T, U)
      def initialize(@bar : T, @baz : U)
      end
    end
    
    Foo.new String, Int32
    

    我不知道你确切的用例,但你可能不需要这些值作为类 . 无论如何你可能无法做很多事情并从你的例子中得出我认为这主要是为了显示调试信息 .

    因此,只存储类的名称(作为字符串)很可能是解决此问题的更好方法 .

    # better solution
    class Foo
      @bar : String
      @baz : String
      def initialize(bar : Class, baz : Class)
        @bar = bar.name
        @baz = baz.name
      end
    end
    
    Foo.new String, Int3
    

    泛型参数意味着为 Foo 使用的每个类组合创建一个新的具体类型 . 这可能会对编译器性能产生影响 .

    我绝对会使用字符串 . 即使您稍后需要某些特殊处理的类,最好只使用宏生成的查找表将字符串映射到常量 .

  • 3

    试试generics

    class BadType(ClassA, ClassB) < Exception
      getter should_be : ClassA
      getter actual : ClassB
    
      def initialize(@should_be, @actual)
        @message = "Bad type: should be #{@should_be}, actual is #{@actual}"
      end
    end
    
    def feed(pet : Animal, food : Food)
      raise BadType(Animal.class, Animal.class).new should_be: Cat, actual: pet.class if food == "fish" && !pet.is_a?(Cat)
    end
    
    class Animal
    end
    
    record Food, food : String do
      def ==(other_food)
        @food == other_food
      end
    end
    
    class Cat < Animal
    end
    
    class Dog < Animal
    end
    
    feed pet: Dog.new, food: Food.new("fish")
    

    输出:

    Unhandled exception: Bad type: should be Cat, actual is Dog (BadType(Animal:Class, Animal:Class))
      from /eval:11:3 in 'feed'
      from /eval:29:1 in '__crystal_main'
      from /usr/lib/crystal/crystal/main.cr:104:5 in 'main_user_code'
      from /usr/lib/crystal/crystal/main.cr:93:7 in 'main'
      from /usr/lib/crystal/crystal/main.cr:133:3 in 'main'
      from __libc_start_main
      from _start
      from ???
    

    演示:https://carc.in/#/r/4pgs

相关问题