在 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 分支之外,编译器不知道 varcasted_arg 的类型总是 String, StringInt32, 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"

另一种选择可能是使用宏来实现此操作以避免重复操作。这应该是可行的,但它也可以在没有宏的情况下工作,所以没有强烈的需要这样做。