crystal lang :在 Class 作为字段的情况下
crystal lang : in case of a Class as a field
我只是在编写一个异常,它应该存储一个 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,这是否意味着永远不能将 Class
对象存储为字段?但在这里我的问题是一个有意义的用法(任何类型检查取决于输入可能需要这个BadType
)。
不知道是不是漏掉了什么,先来了
Class
不能(还)用作 ivar 类型。也许永远不会,我不知道。
但是您实际上可以对具体数据类型使用泛型,从构造函数的参数推断:
# 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
的每个组合创建一个新的具体类型。这会对编译器性能产生影响。
我绝对会为此使用字符串。即使您稍后需要 类 进行某些特殊处理,最好只使用宏生成的查找 table.
将字符串映射到常量
尝试 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 ???
我只是在编写一个异常,它应该存储一个 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,这是否意味着永远不能将 Class
对象存储为字段?但在这里我的问题是一个有意义的用法(任何类型检查取决于输入可能需要这个BadType
)。
不知道是不是漏掉了什么,先来了
Class
不能(还)用作 ivar 类型。也许永远不会,我不知道。
但是您实际上可以对具体数据类型使用泛型,从构造函数的参数推断:
# 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
的每个组合创建一个新的具体类型。这会对编译器性能产生影响。
我绝对会为此使用字符串。即使您稍后需要 类 进行某些特殊处理,最好只使用宏生成的查找 table.
将字符串映射到常量尝试 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 ???