from_json 不适用于录制宏?
from_json doesn't work with record macro?
为什么 from_json
对使用 record
宏创建的 struct
不起作用?
require "json"
record Stock,
symbol : String,
name : String
p Stock.from_json %({ "symbol": "MSFT", "name": "Some" })
错误
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)
问题二:
堆栈跟踪没有行号,我尝试使用--error-trace
但它没有效果,我如何使用--error-trace
?
> crystal api/crystal/play.cr --error-trace
Showing last frame. Use --error-trace for full trace.
In /crystal-1.1.1-1/src/json/from_json.cr:13:3
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)
P.S.
我找到了解决方案,不过如果它能正常工作会更好,而不需要包含 JSON::Serializable
record Stock,
symbol : String,
name : String,
do
include JSON::Serializable
end
你已经想通了。关于是否应始终包含 JSON::Serialize 的问题,这意味着 JSON 支持可用(require "json"
)。否则,它不会编译。我认为这就是默认情况下它没有被烘焙的原因。
关于原题,有调试宏的方法。如果在宏的末尾包含 {% debug %}
,它将打印生成的代码。我在您的示例中通过复制 record macro (sources are here) 的源代码进行了尝试,仅通过 my_record
:
重命名 record
macro my_record(name, *properties)
struct {{name.id}}
{% for property in properties %}
{% if property.is_a?(Assign) %}
getter {{property.target.id}}
{% elsif property.is_a?(TypeDeclaration) %}
getter {{property}}
{% else %}
getter :{{property.id}}
{% end %}
{% end %}
def initialize({{
*properties.map do |field|
"@#{field.id}".id
end
}})
end
{{yield}}
def copy_with({{
*properties.map do |property|
if property.is_a?(Assign)
"#{property.target.id} _#{property.target.id} = @#{property.target.id}".id
elsif property.is_a?(TypeDeclaration)
"#{property.var.id} _#{property.var.id} = @#{property.var.id}".id
else
"#{property.id} _#{property.id} = @#{property.id}".id
end
end
}})
self.class.new({{
*properties.map do |property|
if property.is_a?(Assign)
"_#{property.target.id}".id
elsif property.is_a?(TypeDeclaration)
"_#{property.var.id}".id
else
"_#{property.id}".id
end
end
}})
end
def clone
self.class.new({{
*properties.map do |property|
if property.is_a?(Assign)
"@#{property.target.id}.clone".id
elsif property.is_a?(TypeDeclaration)
"@#{property.var.id}.clone".id
else
"@#{property.id}.clone".id
end
end
}})
end
end
{% debug %}
end
注意最后的{% debug %}
。现在当运行你的例子...
my_record Stock,
symbol : String,
name : String
... 它扩展为:
struct Stock
getter symbol : String
getter name : String
def initialize(@symbol : String, @name : String)
end
def copy_with(symbol _symbol = @symbol, name _name = @name)
self.class.new(_symbol, _name)
end
def clone
self.class.new(@symbol.clone, @name.clone)
end
end
此外,--error-trace
参数应该有效。我没有用 crystal play
试过,但你可以用 crystal run
。该选项必须位于文件名之前:
$ crystal run --error-trace example.cr
struct Stock
getter symbol : String
getter name : String
def initialize(@symbol : String, @name : String)
end
def copy_with(symbol _symbol = @symbol, name _name = @name)
self.class.new(_symbol, _name)
end
def clone
self.class.new(@symbol.clone, @name.clone)
end
end
In example.cr:70:9
70 | p Stock.from_json %({ "symbol": "MSFT", "name": "Some" })
^--------
Error: instantiating 'Stock.class#from_json(String)'
In /usr/lib/crystal/json/from_json.cr:13:3
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)
为什么 from_json
对使用 record
宏创建的 struct
不起作用?
require "json"
record Stock,
symbol : String,
name : String
p Stock.from_json %({ "symbol": "MSFT", "name": "Some" })
错误
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)
问题二:
堆栈跟踪没有行号,我尝试使用--error-trace
但它没有效果,我如何使用--error-trace
?
> crystal api/crystal/play.cr --error-trace
Showing last frame. Use --error-trace for full trace.
In /crystal-1.1.1-1/src/json/from_json.cr:13:3
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)
P.S.
我找到了解决方案,不过如果它能正常工作会更好,而不需要包含 JSON::Serializable
record Stock,
symbol : String,
name : String,
do
include JSON::Serializable
end
你已经想通了。关于是否应始终包含 JSON::Serialize 的问题,这意味着 JSON 支持可用(require "json"
)。否则,它不会编译。我认为这就是默认情况下它没有被烘焙的原因。
关于原题,有调试宏的方法。如果在宏的末尾包含 {% debug %}
,它将打印生成的代码。我在您的示例中通过复制 record macro (sources are here) 的源代码进行了尝试,仅通过 my_record
:
record
macro my_record(name, *properties)
struct {{name.id}}
{% for property in properties %}
{% if property.is_a?(Assign) %}
getter {{property.target.id}}
{% elsif property.is_a?(TypeDeclaration) %}
getter {{property}}
{% else %}
getter :{{property.id}}
{% end %}
{% end %}
def initialize({{
*properties.map do |field|
"@#{field.id}".id
end
}})
end
{{yield}}
def copy_with({{
*properties.map do |property|
if property.is_a?(Assign)
"#{property.target.id} _#{property.target.id} = @#{property.target.id}".id
elsif property.is_a?(TypeDeclaration)
"#{property.var.id} _#{property.var.id} = @#{property.var.id}".id
else
"#{property.id} _#{property.id} = @#{property.id}".id
end
end
}})
self.class.new({{
*properties.map do |property|
if property.is_a?(Assign)
"_#{property.target.id}".id
elsif property.is_a?(TypeDeclaration)
"_#{property.var.id}".id
else
"_#{property.id}".id
end
end
}})
end
def clone
self.class.new({{
*properties.map do |property|
if property.is_a?(Assign)
"@#{property.target.id}.clone".id
elsif property.is_a?(TypeDeclaration)
"@#{property.var.id}.clone".id
else
"@#{property.id}.clone".id
end
end
}})
end
end
{% debug %}
end
注意最后的{% debug %}
。现在当运行你的例子...
my_record Stock,
symbol : String,
name : String
... 它扩展为:
struct Stock
getter symbol : String
getter name : String
def initialize(@symbol : String, @name : String)
end
def copy_with(symbol _symbol = @symbol, name _name = @name)
self.class.new(_symbol, _name)
end
def clone
self.class.new(@symbol.clone, @name.clone)
end
end
此外,--error-trace
参数应该有效。我没有用 crystal play
试过,但你可以用 crystal run
。该选项必须位于文件名之前:
$ crystal run --error-trace example.cr
struct Stock
getter symbol : String
getter name : String
def initialize(@symbol : String, @name : String)
end
def copy_with(symbol _symbol = @symbol, name _name = @name)
self.class.new(_symbol, _name)
end
def clone
self.class.new(@symbol.clone, @name.clone)
end
end
In example.cr:70:9
70 | p Stock.from_json %({ "symbol": "MSFT", "name": "Some" })
^--------
Error: instantiating 'Stock.class#from_json(String)'
In /usr/lib/crystal/json/from_json.cr:13:3
13 | new parser
^--
Error: wrong number of arguments for 'Stock.new' (given 1, expected 2)
Overloads are:
- Stock.new(symbol : String, name : String)