julia Match.jl 与日期匹配错误 - 模式需要 3 个字段

问题描述 投票:0回答:1

刚刚更新了我的项目部门,并使用 Match.jl @match 语句收到此错误。

ERROR: The type `Dates.Date` has 1 fields but the pattern expects 3 fields.
    
@match date begin
    Date(2023, 4, 10) => true # Monday after Easter
    Date(2023, 5, 1) => true # May Day?
end

Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:35
  [2] bind_pattern!(location::LineNumberNode, source::Expr, input::Symbol, binder::Match.BinderContext, assigned::Base.ImmutableDict{Symbol, Symbol})
    @ Match ~/.julia/packages/Match/SZDEk/src/binding.jl:244
  [3] bind_case(case_number::Int64, location::LineNumberNode, case::Expr, predeclared_temps::Vector{Any}, binder::Match.BinderContext)
    @ Match ~/.julia/packages/Match/SZDEk/src/binding.jl:580
  [4] build_automaton_core(value::Symbol, source_cases::Vector{Any}, location::LineNumberNode, predeclared_temps::Vector{Any}, binder::Match.BinderContext)
    @ Match ~/.julia/packages/Match/SZDEk/src/match_cases_opt.jl:15
  [5] build_automaton(location::LineNumberNode, mod::Module, value::Any, body::Expr)
    @ Match ~/.julia/packages/Match/SZDEk/src/match_cases_opt.jl:149
  [6] build_deduplicated_automaton
    @ ~/.julia/packages/Match/SZDEk/src/match_cases_opt.jl:158 [inlined]
  [7] handle_match_cases(location::LineNumberNode, mod::Module, value::Symbol, body::Expr)
    @ Match ~/.julia/packages/Match/SZDEk/src/match_cases_opt.jl:477
  [8] var"@match"(__source__::LineNumberNode, __module__::Module, value::Any, cases::Any)
    @ Match ~/.julia/packages/Match/SZDEk/src/matchmacro.jl:114
  [9] include(mod::Module, _path::String)
    @ Base ./Base.jl:457
 [10] include(x::String)
    @ Main.Tibra ~/src/tibra/Tibra.jl/src/Tibra.jl:1
 [11] top-level scope
    @ ~/src/tibra/Tibra.jl/src/Tibra.jl:101
 [12] include(fname::String)
    @ Base.MainInclude ./client.jl:478
 [13] top-level scope
    @ ~/src/tibra/Tibra.jl/scripts/run_tibrax_server.jl:1
julia match
1个回答
0
投票

简短回答

在模式中插入

Date
函数:

using Match, Dates

date = Date(2023, 5, 1)

check = @match date begin
    $(Date(2023, 4, 10)) => true
    $(Date(2023, 5, 1)) => false
end

@assert check == false

或者您可以使用模式的内部构造函数

Date(::Dates.UTInstant{Day})

date = Date(2023, 4, 10)

check = @match date begin
    Date(Dates.UTInstant(Day(738620)) => true
    Date(Dates.UTInstant(Day(738642)) => false
end

@assert check == true

长答案

对于 multi-case

@match
,Match.jl 要求模式为以下之一:

  • 一个值
  • 正则表达式
  • 类型检查或 构造函数
  • 元组
  • 数组

Match.jl 仅将参数数量与结构成员相同的构造函数视为此定义中的“构造函数”。它不认为“外部构造函数”是构造函数,这就是

Date(y, m, d)
是什么。您可以通过创建一个具有两个构造函数的类型来自行检查宏的工作原理:一个具有与结构体参数相同数量的参数,另一个具有其他数量的参数或具有某些不兼容类型的参数,并且
@match 
会抛出类似的异常:

struct Foo
    a::Int
    b::Int
end

Foo(x::String, y::String) = Foo(parse(Int, x), parse(Int, y))
Foo(x::Int) = Foo(x, 0)

foo = Foo(1, 0)

check = @match foo begin
    Foo(1) => true
    Foo(2) => false
end  # throws LoadError because the number of arguments does not match the number of struct parameters

check = @match foo begin
    Foo("1", "0") => true
    Foo("2", "0") => false
end  # throws MatchFailure, even though Foo(::String, ::String) has the right number of arguments and returns an appropriate Foo struct

check = @match foo begin
    Foo(1, 0) => true
    Foo(2, 0) => false
end

@assert check == true  # works

但是,您可以通过简单地在

@match
宏中插入外部构造函数方法的返回值来解决此问题,如文档中所述

check = @match foo begin
    $(Foo(1)) => true  # interpolates to Foo(1, 0)
    $(Foo("2", "0")) => false  # interpolates to Foo(2, 0)
end

@assert check == true

当然,你总是可以这样做:

check = let
    if foo == Foo(1)
        true
    elseif foo == Foo(2)
        false
    end
end

@assert check == true

这基本上就是

@match
宏最终为您做的事情。

© www.soinside.com 2019 - 2024. All rights reserved.