Anonymous variables in Erlang

2019-02-06 02:58发布

问题:

What are the exact differences between underscore variables and a named variable that starts with underscore from the Erlang compiler point of view (apart from adding readability to the code)?

For example are _ and _Var different?

回答1:

The don't care variable _ is a VERY SPECIAL variable which matches anything and is NEVER bound to a value. It is used when I know there is something there but I don't care what the value is and I will never use. Seeing _ is never bound it can not be used in an expression and the compiler flags it as an error.

Variables like _Var are perfectly normal variables which you can match against and will be bound to values which means they can be used in expressions. Prefixing a variable with _ is about intent. The compiler normally warns you about a variable which is bound in a pattern but is never used, often a sign of an error. But the compiler does not warn for variables prefixed with _ like in _Var. The intent being that I want to give the variable a name, naming things is good, but that I know I will never use it.

Remember that _ is really the only special variable and that _Var are normal variables and behave as such if used. If you are feeling perverse then you could prefix all your variables with _ and everything will still work.



回答2:

Let's quote the doc here:

The anonymous variable is denoted by underscore (_) and can be used when a variable is required but its value can be ignored. [...]

Variables starting with underscore (_), for example _Height, are normal variables, not anonymous: they are however ignored by the compiler in the sense that they will not generate any warnings for unused variables.

In other words, you use _Var form when you need the matched expression to be matched - but don't want to use it further AND/OR you want show its meaning. And you use _ variable when neither you nor compiler should care for the expression that will be matched by it.

Example 1:

member(_, []) -> [].

In this function is not quite clear what the first _ matches. But rewriting it directly, like this:

member(Elem, []) -> [].

... will generate a warning, if the code is compiled with the flag warn_unused_vars set. You still can make you code readable here, though, by using underscored variable:

member(_Elem, []) -> [].

Example 2:

{_, _, Some} = {1, 2, 3}

This tuple matching will go though quite all right, as the first two elements of tuple will be ignored completely.

{_Var, _Var, Some} = {1, 2, 3}

This matching will fail, however: though _Var won't have to be used, it should be 'filled' with the same value! As 1 is not equal to 2, the condition fails here.