在 Crystal 中自动转换 - 我可以告诉编译器忽略类型错误吗? (例如在指令中)
Auto-Cast in Crystal - Can I tell the compiler to ignore type errors? (E.G. in a directive)
取以下代码:
class Test(T)
def initialize(var : T)
@var = var
end
def +(val)
if @var.is_a? String
casted_arg = val.to_s
else
casted_arg = typeof(@var).new(val)
end
return @var + casted_arg
end
end
puts Test.new(1) + "1" #=>2
puts Test.new("1") + 1 #=>"11"
如果我尝试编译它,我会得到一个编译器错误:no overload matches ...
如果我定义+(val)
如下:
def +(val)
casted_arg = typeof(@var).new(val)
return @var + casted_arg
end
然后 puts Test.new(1) + "1"
按预期工作 (#=>2) 和 puts Test.new("1") + 1
错误(显然未处理)。
但是如果我定义 +(val)
如下:
def +(val)
casted_arg = val.to_s
return @var + casted_arg
end
然后 puts Test.new("1") + 1
按预期工作(#=>“11”)和 puts Test.new(1) + "1"
错误(显然未处理)。
最后,理论上我很确定我拥有的代码:
def +(val)
if @var.is_a? String
casted_arg = val.to_s
else
casted_arg = typeof(@var).new(val)
end
return @var + casted_arg
end
应该涵盖所有情况?为什么不编译?由于基于类型的编译错误。通常在这种情况下我会使用宏,但是问题是你不能在宏中使用 is_a?
或 typeof()
...所以我想也许 {%begin%}-{%rescue%}-{%end%}
可能存在,但不幸的是它没有。
我一直在绞尽脑汁,我真的看不出任何解决办法,除非我可以向编译器声明"Hey can you just ignore compilation errors in the next declaration and just 'assume' it's going to work out?"
真的没有实现这种行为的干净方法吗?
您的代码中的类型推断存在两个问题。首先,正如编译器错误所说,在 if/else 分支之后,casted_var
的类型是可以在两个分支中分配的所有类型的联合:Int32 | String
。
在 if
分支之外,编译器不知道 var
和 casted_arg
的类型总是 String, String
或 Int32, Int32
。
我不确定,但是也许 类型推断算法可以解决这个问题。有一天它可能会变得那么聪明。但现在不是。
现在,您必须将操作移至 if/else 分支以匹配正确的类型。
另一个问题只是将 @var
存储在局部变量中(请参阅 if var.is_a? 上关于实例变量的文档。
class Test(T)
def initialize(var : T)
@var = var
end
def +(val)
var = @var
if var.is_a? String
casted_arg = val.to_s
return var + casted_arg
else
casted_arg = typeof(var).new(val)
return var + casted_arg
end
end
end
puts Test.new(1) + "1" #=>2
puts Test.new("1") + 1 #=>"11"
另一种选择可能是使用宏来实现此操作以避免重复操作。这应该是可行的,但它也可以在没有宏的情况下工作,所以没有强烈的需要这样做。
取以下代码:
class Test(T)
def initialize(var : T)
@var = var
end
def +(val)
if @var.is_a? String
casted_arg = val.to_s
else
casted_arg = typeof(@var).new(val)
end
return @var + casted_arg
end
end
puts Test.new(1) + "1" #=>2
puts Test.new("1") + 1 #=>"11"
如果我尝试编译它,我会得到一个编译器错误:no overload matches ...
如果我定义+(val)
如下:
def +(val)
casted_arg = typeof(@var).new(val)
return @var + casted_arg
end
然后 puts Test.new(1) + "1"
按预期工作 (#=>2) 和 puts Test.new("1") + 1
错误(显然未处理)。
但是如果我定义 +(val)
如下:
def +(val)
casted_arg = val.to_s
return @var + casted_arg
end
然后 puts Test.new("1") + 1
按预期工作(#=>“11”)和 puts Test.new(1) + "1"
错误(显然未处理)。
最后,理论上我很确定我拥有的代码:
def +(val)
if @var.is_a? String
casted_arg = val.to_s
else
casted_arg = typeof(@var).new(val)
end
return @var + casted_arg
end
应该涵盖所有情况?为什么不编译?由于基于类型的编译错误。通常在这种情况下我会使用宏,但是问题是你不能在宏中使用 is_a?
或 typeof()
...所以我想也许 {%begin%}-{%rescue%}-{%end%}
可能存在,但不幸的是它没有。
我一直在绞尽脑汁,我真的看不出任何解决办法,除非我可以向编译器声明"Hey can you just ignore compilation errors in the next declaration and just 'assume' it's going to work out?"
真的没有实现这种行为的干净方法吗?
您的代码中的类型推断存在两个问题。首先,正如编译器错误所说,在 if/else 分支之后,casted_var
的类型是可以在两个分支中分配的所有类型的联合:Int32 | String
。
在 if
分支之外,编译器不知道 var
和 casted_arg
的类型总是 String, String
或 Int32, Int32
。
我不确定,但是也许 类型推断算法可以解决这个问题。有一天它可能会变得那么聪明。但现在不是。
现在,您必须将操作移至 if/else 分支以匹配正确的类型。
另一个问题只是将 @var
存储在局部变量中(请参阅 if var.is_a? 上关于实例变量的文档。
class Test(T)
def initialize(var : T)
@var = var
end
def +(val)
var = @var
if var.is_a? String
casted_arg = val.to_s
return var + casted_arg
else
casted_arg = typeof(var).new(val)
return var + casted_arg
end
end
end
puts Test.new(1) + "1" #=>2
puts Test.new("1") + 1 #=>"11"
另一种选择可能是使用宏来实现此操作以避免重复操作。这应该是可行的,但它也可以在没有宏的情况下工作,所以没有强烈的需要这样做。