如何重载相等运算符?

时间:2019-05-31 20:10:26

标签: elixir

例如,在swift中,您可以按如下方式重载等于运算符:

Overloading equivalence (==) operator for custom class in Swift

class CustomClass: Equatable {
    var id = "my id"
}

func ==(left: CustomClass, right: CustomClass) -> Bool {
    return left.id == right.id
}

在长生不老药中有办法吗?

我想实现的是这样:

defmodule IP do
  @enforce_keys [:host, :port]
  defstruct [:host, :port, failures: 0, timeouts: 0]

  @type t :: %IP{host: String.t(), port: integer, failures: integer, timeouts: integer}

  # I want the == operator compare host and port but not failures and timeouts..
  def compare(l, r) do
    l.host == r.host && l.port == r.port
  end
end

2 个答案:

答案 0 :(得分:0)

defmodule IP do
  defstruct [:host, :port, :name]

  def left_ip == right_ip do
    Kernel.==(left_ip.host, right_ip.host) &&
    Kernel.==(left_ip.port, right_ip.port)
  end

end

在iex中:

~/elixir_programs$ iex ip.ex
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> left_ip = %IP{host: 10, port: 3, name: "Joe"}   
%IP{host: 10, name: "Joe", port: 3}

iex(2)> right_ip = %IP{host: 10, port: 3, name: "Karen"}
%IP{host: 10, name: "Karen", port: 3}

iex(3)> left_ip == right_ip
false

iex(4)> import Kernel, except: [==: 2]
Kernel

iex(5)> left_ip == right_ip           
** (CompileError) iex:5: undefined function ==/2

iex(5)> import IP                     
IP

iex(6)> left_ip == right_ip
true

内核会自动导入到iex中,因此除了功能Kernel.==()之外,您必须再次导入内核。

import statement与命名空间有关。通过导入IP,您不再需要在函数名称之前添加模块名称:

IP.==(left, right)

v.

left == right
  

我希望在插入MapSet时将结构进行相等比较

使用MapSet无效:

iex(24)> left_ip == right_ip
true

iex(27)> ms = MapSet.new()  
#MapSet<[]>                                                

iex(28)> ms |> MapSet.put("hello") |> MapSet.put(left_ip) |> MapSet.put("hello") |> MapSet.put(right_ip) |> MapSet.put(left_ip) 
#MapSet<[
  %IP{host: 10, name: "Joe", port: 3},
  %IP{host: 10, name: "Karen", port: 3},
  "hello"
]>

Mapset.put调用Map.put,后者调用:maps.put,这是一个erlang函数。

答案 1 :(得分:0)

虽然开箱即用MapSet无法实现,但是可以很容易地自己实现。 MapSetno-brainer,是一张简单的地图。

defmodule IPs do
  defstruct m: %{}

  def put_new(%IPs{m: m}, %IP{host: host, port: port} = ip)
    %IPs{m | Map.put_new(m, {host, port}, {host, port}, ip)}
  end

  def values(%IPs{m: m}), do: Map.values(m)
end

您还可以实现Access行为,或将所需的所有功能委派给基础映射,或复制整个MapSet行为。