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?
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
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
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.