web-dev-qa-db-fra.com

Fonction de correspondance de motif contre une carte vide

Je joue avec la correspondance de motifs et j'ai découvert qu'il n'est pas très facile de faire correspondre les paramètres d'une méthode à une carte vide. Je pensais que ça irait quelque chose comme ça:

defmodule PatternMatch do
  def modify(%{}) do
    %{}
  end

  def modify(map) do
    # expensive operation
    %{ modified: "map" }
  end
end

Mais il semble que la première clause de fonction corresponde à des cartes arbitraires:

iex> PatternMatch.modify(%{a: "map"})
==> %{}

Existe-t-il un autre moyen de vérifier les cartes vides?

43
leifg

Cela fonctionne de cette façon par conception, mais il peut certes être un peu déroutant à première vue. Cette fonctionnalité vous permet de détruire des cartes en utilisant la correspondance de motifs, sans avoir à spécifier toutes les clés. Par exemple:

iex> %{b: value} = %{a: 1, b: 2, c: 3}
%{a: 1, b: 2, c: 3}

iex> value
2

Par conséquent, %{} correspondra à n'importe quelle carte. Si vous voulez faire correspondre une carte vide dans une fonction, vous devez utiliser une clause de garde:

defmodule PatternMatch do
  def modify(map) when map == %{} do
    %{}
  end

  def modify(map) do
    # ...
  end
end
75
Patrick Oscity

En plus de la réponse de @ PatrickOscity (que j'utiliserais pour une carte vide), vous pouvez utiliser un map_size/1 garde pour faire correspondre les cartes avec un certain nombre de clés:

defmodule PatternMatch do
  def modify(map) when map_size(map) == 0 do
    %{}
  end

  def modify(map) when map_size(map) == 1 do
    #something else
  end

  def modify(map) do
    # expensive operation
    %{ modified: "map" }
  end
end

Voici une sortie de iex utilisant Kernel.match?/2 montrer map_size/1 en action:

iex(6)> Kernel.match?(map when map_size(map) == 1, %{})
false
iex(7)> Kernel.match?(map when map_size(map) == 1, %{foo: "bar"})
true
23
Gazler

En plus de toutes les réponses intéressantes fournies jusqu'à présent, vous pouvez également envisager l'utilisation de opérateur de broche unaire qui ressemble à un chapeau ou à un point de flèche supérieur. Vous l'utilisez pour préfixer une variable avec elle pour vous assurer que votre modèle correspond à sa valeur, comme indiqué dans la documentation pertinente:

Utilisez l'opérateur de broche ^ lorsque vous souhaitez faire correspondre le motif à la valeur d'une variable existante plutôt que de relier la variable

Voici un exemple:

defmodule A do
  def determine_map_volume(some_map) do
    an_empty_map = %{}

    some_map
    |> case do
    ^an_empty_map -> :empty  # Application of pin operator
    _ -> :not_empty
    end
  end
end

Que vous pouvez vérifier comme suit:

A.determine_map_volume(%{})
:empty
A.determine_map_volume(%{a: 1})
:not_empty

La méthode que vous comptez utiliser dépend de vos préférences personnelles/organisationnelles pour la lisibilité de votre code.

0
Kevin Johnson