水晶语言-跨宏宏变量

时间:2018-06-21 19:01:40

标签: crystal-lang

因此,我正在构建一个数据类型,我想在其中选择可选自动广播The last question I asked is related to this also.

我当前拥有的代码可以在下面找到:

class Test(T)
  @@auto_cast = false

  def initialize(var : T)
    @var = var
  end
  def self.auto_cast
    @@auto_cast
  end
  def self.auto_cast=(val)
    @@auto_cast = val
  end

  def self.auto_cast(forced_value=true,&block)
    #Force value, but store initial value:
    ac = @@auto_cast
    @@auto_cast = forced_value
      block.call
    @@auto_cast = ac
  end

  def +(val)
    var = @var
    if @@auto_cast
      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
    else
      if typeof(var) != typeof(val)
        {{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
      else
        return var + val
      end
    end
  end
end

但是,当我尝试测试数据类型时:

Test.auto_cast do
  puts Test.auto_cast
  puts Test.new(1) + "1"
  puts Test.new("1") + 1
end

它在return var + val处引发了错误:

  if typeof(var) != typeof(val)
    {{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
  else
    ERROR! --> return var + val
  end

起初我很困惑为什么,但是现在很有意义。

  1. 我相信Crystal编译器无法确定@@auto_cast会在我打算进行auto_cast时为真(公平地说,禁用自动广播时,我希望语法错误)。
  2. 发生编译错误,因为@@auto_cast的值在编译时未知。
  3. 由于身体的矛盾性:

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

  if typeof(var) != typeof(val)
    {{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
  else
    return var + val
  end

每个定义仅应在用户明确声明时使用。因此,这更适合于宏。

鉴于这些原因,我开始尝试将功能构建到宏中:

  def +(val)
    var = @var
    {%if @@auto_cast%}
      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
    {%else%}
      if typeof(var) != typeof(val)
        {{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
      else
        return var + val
      end
    {%end%}
  end

我认为这会起作用,因为只有在设置@@auto_cast的情况下,这种方式才会生成代码。但是,我忘记的是前提2。即@@auto_cast的值在编译时未知。最终,为了完成这项工作,我需要一个变量,可以是:

  1. 在编译时设置。
  2. 在编译时在宏内全局使用。

我最终认为我可以按照以下方式做点事情:

SET_AUTOCAST_VARIABLE true
  puts Test.auto_cast
  puts Test.new(1) + "1"
  puts Test.new("1") + 1
SET_AUTOCAST_VARIABLE false

,然后在+()定义中:

{%if autocast_variable %}
   ...
{%else%}
   ...
{%end%}

问题是,我不认为存在这样的宏全局变量 ...我正在考虑解决该问题的方法,到目前为止,我唯一能想到的解决方案是使用一些外部文件在编译时:

{{File.write("/tmp/cct","1")}}
  puts Test.auto_cast
  puts Test.new(1) + "1"
  puts Test.new("1") + 1
{{File.write("/tmp/cct","")}}

以及方法定义中:

{%if File.read("/tmp/cct")=="1" %}
   ...
{%else%}
   ...
{%end%}

虽然这感觉真的很棘手...我想知道是否还有其他选择(或者,即使这根本行不通)?

1 个答案:

答案 0 :(得分:2)

这行不通。方法仅实例化一次,不可能有两个具有相同参数类型的相同方法的实现。在下面的示例中,两个20000000 <Vectors>: 20000000: 20005000 andcs r5, r0, r0 20000004: 200001e7 andcs r0, r0, r7, ror #3 20000008: 200001e5 andcs r0, r0, r5, ror #3 2000000c: 200001e5 andcs r0, r0, r5, ror #3 20000010: 200001e5 andcs r0, r0, r5, ror #3 20000014: 200001e5 andcs r0, r0, r5, ror #3 20000018: 200001e5 andcs r0, r0, r5, ror #3 ... 200001e0: f000 b801 b.w 200001e6 <Reset_Handler> 200001e4 <HardFault_Handler>: 200001e4: e7fe b.n 200001e4 <HardFault_Handler> 200001e6 <Reset_Handler>: ... 方法将不可避免地具有相同的实现。

+

根据词法范围,您不能具有相同方法的不同实现。该方法仅被实例化一次,其内部的宏也是如此。

我不了解您的总体用例,但是也许还有其他方法可以满足您的需求。


出于完整性考虑:您可以将常量用作宏全局变量。常量无法重新定义,但可以通过宏表达式进行更改。可以用来在宏之间存储状态。例如:

Test.auto_cast do
  Test.new(1) + "1"
end
Test.new(1) + "1"

但是,这很hacky)

相关问题