¿Alguien puede explicar por qué al devolver $ false de una función de PowerShell no puede usar un operador de comparación para determinar si la función ha devuelto $ false pero cuando devuelve $ true la comparación se evalúa como $ true?

function boolean {
    return $false
}

boolean -eq $false

function boolean {
    return $true
}

boolean -eq $true

>>>False
>>>True

Puede solucionar esto configurando la llamada de función a una variable, pero me preguntaba si alguien podría explicar qué está sucediendo aquí debajo del capó.

function boolean {
    return $false
}

$bool = boolean 
$bool -eq $false

function boolean {
    return $true
}

$bool = boolean
$bool -eq $true

>>>True
>>>True
5
Bob 14 feb. 2018 a las 00:46

2 respuestas

La mejor respuesta

PowerShell tiene dos modos de análisis fundamentales :

  • argumento modo , que funciona como los tradicionales shells

    • En el modo de argumento, el primer token se interpreta como un nombre de comando (como el nombre del cmdlet, el nombre de la función o el nombre de archivo de un ejecutable), seguido por una lista separada por espacios en blanco de argumentos .
  • Modo expresión , que funciona como los lenguajes de programación tradicionales.

Ejecutando Get-help about_Parsing proporciona una introducción a estos modos; en resumen, es el primer token que determina qué modo se aplica.
También tenga en cuenta que una declaración determinada puede estar compuesta de partes que se analizan en cualquier modo.


boolean -eq $false se analiza en modo argumento , porque su primer token parece un nombre de comando (un identificador que podría ser un nombre de programa, un nombre de cmdlet, un nombre de función o un alias).

Por lo tanto, -eq y $false se interpretan como argumentos (valores de parámetros) para pasar a la función boolean .

Dado que sus funciones boolean están definidas de una manera que no impone el paso de valores solo a parámetros declarados , los argumentos se ignoran de manera efectiva y el resultado de la declaración es cualquier salida de la función ($false o $true).

Como se demuestra en respuesta de Mike Shepard, puede hacer que una función aplique el uso de solo parámetros declarados (incluido none ) con un bloque param() decorado con el atributo [CmdletBinding()], que al menos daría como resultado un error si pasas argumentos inadvertidamente a la función boolean sin parámetros.

Puede solucionar esto configurando la llamada de función a una variable

$bool = boolean   # execute function and capture result in variable
$bool -eq $false  # use variable in the comparison 

La razón por la que esto funciona es que la instrucción -eq comienza con $ , una referencia de variable en este caso, lo que hace que PowerShell analice en modo expresión , donde -eq se reconoce como un operador y $false como su RHS.

Sin embargo, no es necesario realizar este paso intermedio:

Para forzar que un fragmento de código se interprete como una expresión , enciérrelo entre (...) :

(boolean) -eq $false # Calls function 'boolean' and uses result as LHS of -eq

(...) fuerza un nuevo contexto de análisis (que en sí mismo se analiza en modo de argumento o expresión, de nuevo según el primer token) y trata el resultado como una expresión . que luego permite su uso como parte de una expresión más grande , como un operando del operador -eq, o como un argumento de comando .

7
mklement0 14 feb. 2018 a las 13:41

PowerShell ve -eq como el nombre de un parámetro que se pasa a la función "booleana".

Para ver esto, puede poner la función llamada en parens:

function boolean {
    return $false
}

(boolean) -eq $false

function boolean {
    return $true
}

(boolean) -eq $true

O puede convertirla en una función avanzada para que obtenga un error con el parámetro faltante (-eq):

function boolean {
[CmdletBinding()]
Param()
    return $false
}

boolean -eq $false

function boolean {
[CmdletBinding()]
Param()
    return $true
}

boolean -eq $true
5
Mike Shepard 13 feb. 2018 a las 22:04