简体   繁体   English

Elixir:为映射指定`key_type`,其中`key_type` 是枚举类型

[英]Elixir: Specifying `key_type` for a map, where `key_type` is an enumerated type

I have a function that returns a map which I would like to define a custom type for.我有一个返回地图的函数,我想为其定义自定义类型。

The process of doing it has been pretty easy, except when dealing with key_type from the docs here:这样做的过程非常简单,除了处理此处文档中的key_type时:

%{required(key_type) => value_type} # map with required pairs of key_type and value_type

For this new type I'm defining, key_type should be any string that is a representation of the current year or a year in the future.对于我定义的这个新类型, key_type应该是表示当前年份或未来年份的任何字符串。

Keys like "2019" or "2025 are good, but keys like "2008" are no good."2019""2025 "2008"这样的键很好,但像"2008"这样的键就不好。

I was hoping this would work:我希望这会奏效:

  @type home_sharing_rate :: number
  @type home_sharing_days :: [number]
  @type home_sharing_booking :: { home_sharing_days, home_sharing_rate }

  @type income_year :: "2019" | "2020" | "2021" | "2022" | "2023"
  @type income_month :: "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"

  @type earned_home_sharing_income_summary :: %{ required(income_year) => %{ required(income_month ) => [home_sharing_booking] } }

but no such luck.但没有这样的运气。 However, I see that Elixir has some built-in types like non_neg_integer() which lead me to believe I could define a type as an enumeration, but now I'm not so sure.但是,我看到 Elixir 有一些内置类型,例如non_neg_integer() ,这让我相信我可以将类型定义为枚举,但现在我不太确定。 Is there any way to do this?有没有办法做到这一点?

TypeScript has plenty of tools to make this happen so I was kind of hoping Elixir did as well. TypeScript 有很多工具可以实现这一点,所以我有点希望 Elixir 也能做到。 To me, it seems odd that a type can't be defined as an enumeration of its values, but perhaps the way that Elixir intends types to be used is different than Typescript and I'm just missing something.对我来说,类型不能被定义为其值的枚举似乎很奇怪,但也许 Elixir 打算使用类型的方式与 Typescript 不同,我只是遗漏了一些东西。

Typespecs only handle binaries specified with <<>> syntax , and, unfortunately, only the size and unit are supported. Typespecs 只处理<<>>语法指定的二进制文件,不幸的是,只支持大小和单位。 This piece of code would produce a more descriptive error message:这段代码会产生更具描述性的错误消息:

defmodule Foo do
  @typep income_year :: <<"2019"::binary-size(4)>> | <<"2020"::binary-size(4)>>
  @type earned :: %{ required(income_year) => any() }
end

results in结果是

** (CompileError) iex:4: invalid binary specification,
  expected <<_::size>>, <<_::_*unit>>, or <<_::size, _::_*unit>>
  with size and unit being non-negative integers

That said, you might resort to @typep income_year :: <<_::binary-size(4)>> at best.也就是说,您@typep income_year :: <<_::binary-size(4)>>

I would suggest to use the guard instead of type whether you are to expect to deal with this type:无论您是否希望处理这种类型,我都建议使用守卫而不是类型:

@allowed_years ~w|2019 2020|
Enum.each(@allowed_years, fn year ->
  def do_something(%{unquote(year) => value} = earned) do
    ...
  end
end)

# sink-all clause
def do_something(_), do: raise "Year is not allowed."

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM