如何通用访问Crystal类中的任意实例变量?
Crystal类实例变量的通用访问方案
1. 用内置宏快速生成getter
Crystal自带getter和property宏,能一键生成实例变量的访问方法,完全不用手动写重复代码:
class Coordinate getter x : Int32, y : Int32 # 自动生成x()和y()只读访问方法 def initialize(x : Int32, y : Int32) @x = x @y = y end end coord = Coordinate.new(10, 20) puts coord.x # 输出10 puts coord.y # 输出20
如果需要同时生成读写方法,把getter换成property就行,这是处理大量变量最高效的方式。
2. 实现动态访问的通用get方法
如果确实需要像你设想的get(var)这种动态访问逻辑,可以用Crystal的反射API instance_variable_get:
class Coordinate def initialize(x : Int32, y : Int32) @x = x @y = y end def get(var : String) instance_variable_get("@#{var}".to_sym) end end coord = Coordinate.new(10, 20) puts coord.get("x") # 输出10 puts coord.get("y") # 输出20
注意:反射会带来一定运行时性能开销,编译型语言里尽量按需使用;另外要确保传入的变量名真实存在,否则会抛出NameError,可以根据需求加错误捕获逻辑。
3. 基于宏实现编译期动态访问
如果想避免运行时反射开销,还可以用Crystal的宏在编译阶段处理访问逻辑:
class Coordinate @x : Int32 @y : Int32 def initialize(x : Int32, y : Int32) @x = x @y = y end macro get(var) @{{var.id}} end end coord = Coordinate.new(10, 20) puts coord.get(x) # 输出10,这里x是编译期已知的符号,不是字符串 puts coord.get(y) # 输出20
这个宏在编译时会直接把get(x)替换成@x,完全没有运行时额外开销,但调用时必须传入编译期就能确定的变量名,不能用运行时生成的字符串。
内容的提问来源于stack exchange,提问作者T. Feix
相关产品推荐
相关产品推荐

