Элегантный способ установки значения по умолчанию для переменной в Powershell 6.0?
У меня есть следующее, которое работает, но выглядит неуклюже:
if($config.contentDir){
$contentDir = $config.contentDir
} else {
$contentDir = "contents"
}
Есть ли способ сделать это лучше? Я видел здесь этот ответ, но он не совсем "лучше". Просто интересно, принесла ли 6.0 какие-либо улучшения?
Я, скорее всего, буду обрабатывать большое количество параметров конфигурации, так что это будет довольно беспорядочно.
4 ответа
Это немного короче...
$contentDir = if ( $config.contentDir ) { $config.contentDir } else { "contents" }
Вы также можете определить iif
функция:
function iif {
param(
[ScriptBlock] $testExpr,
[ScriptBlock] $trueExpr,
[ScriptBlock] $falseExpr
)
if ( & $testExpr ) {
& $trueExpr
}
else {
& $falseExpr
}
}
Тогда вы могли бы сократить до этого:
$contentDir = iif { $config.contentDir } { $config.contentDir } { "contents" }
Кроме того, похоже, что следующая версия PowerShell будет поддерживать тернарный оператор (см. https://devblogs.microsoft.com/powershell/powershell-7-preview-4/), поэтому в будущем вы будете может написать что-то вроде:
$contentDir = $config.contentDir ? $config.contentDir : "contents"
То, что вы ищете, - это объединение нуля, которого в PowerShell нет в версии v7.0.0-preview.4.
А пока для этого нужно будет:
$contentDir = if ($null -eq $config.contentDir) { 'content' } else { $config.contentDir }
Примечание: $null
намеренно размещен на левой стороне -eq
однозначно проверить $null
, потому что как RHS он будет действовать как фильтр, если проверяемое значение будет иметь значение массива.
Адаптация ответа Ли Дейли на основе массива позволяет получить более лаконичное решение:
$contentDir = ($config.ContentDir, 'content')[$null -eq $config.ContentDir]
Использование тернарного оператора (условного), который будет реализован в версии 7.0, позволяет получить аналогичный краткий эквивалент:
$contentDir = $null -eq $config.contentDir ? 'content' : $config.contentDir
Однако все эти подходы имеют следующие нежелательные аспекты:
Они требуют явной ссылки на
$null
; Обратите внимание, чтоif ($config.ContentDir)
- т.е. приведение значения к логическому - может работать со строками, но обычно не является надежным, потому что не-$null
такие ценности, как0
может оценить$false
тоже.$config.contentDir
, значение для проверки$null
, необходимо получить доступ дважды, что может иметь побочные эффекты.
Определение пользовательской функции с именем, скажем,??
, может решить эти проблемы:
# Custom function that emulates null-coalescing.
function ?? ($PossiblyNull, $ValueIfNull) {
if ($null -eq $PossiblyNull) { $ValueIfNull } else { $PossiblyNull }
}
$contentDir = ?? $config.contentDir 'content'
Однако у такой пользовательской функции есть и минусы:
В понижающем стороны пользовательских функций являются:
Вам необходимо включить или импортировать их в каждый фрагмент кода, в котором вы хотите их использовать.
Если вы выберете знакомое имя, например
??
, То размещение операндов может получить в заблуждение, потому что вы должны (всегда) разместить их по- разному в PowerShell, при реализации в качестве функции (например,a ?? b
в C# vs.?? $a $b
в PowerShell) - особенно после того, как в PowerShell будет реализовано истинное слияние нуля: см. следующий раздел.И, конечно же, вызов функции увеличивает накладные расходы.
Если этот запрос функции GitHub будет реализован, вы сможете использовать истинное объединение с нулевым значением, что является одновременно наиболее кратким решением и позволяет избежать вышеупомянутых нежелательных аспектов:
# Hopefully soon
$contentDir = $config.contentDir ?? 'content'
Связанная функция, также предложенная в связанной проблеме GitHub, - это условное присвоение null,$config.ContentDir ?= 'content'
Как Bill_Stewart
показал, что в ps7 есть тернарный оператор. однако вы можете получить нечто подобное, используя массив из двух элементов и пользуясь тем, как PoSh будет приводить значения -$False
дает 0
, $True
дает 1
.
$Config = [PSCustomObject]@{
ContentDir = 'SomewhereElse'
}
#$Config.ContentDir = ''
$ContentDir = @('contents', $Config.ContentDir)[[bool]$Config.ContentDir]
$ContentDir
вывод с закомментированной строкой 4 = SomewhereElse
вывод с включенной строкой 4 = contents
Что-то вроде "||" в баше. Если первое значение false или null, оно выполнит второе.
[void](($contentDir = $config.contentDir) -or ($contentDir = "contents"))