Ловушки Powershell

Суть ответа Starscream верна, но он пропускает , почему , который, как мне кажется, важен здесь. Это сводится к ARC и управлению памятью.

Swift - это язык ссылочных типов и типов значений. Классы являются ссылочными типами, а все остальное - типом значения. Фактически мы на самом деле не указываем, что протокол наследует от class ... это больше похоже на то, что мы указываем, что протокол может быть реализован только с помощью ссылочных типов .

И почему это важно?

Это важно, потому что без него мы не сможем использовать ключевое слово weak с протоколом.

protocol ExampleProtocol {}

class DelegatedClass {
    weak var delegate: ExampleProtocol?
}

Это порождает ошибку:

«слабый» не может применяться к неклассовому типу «ExampleProtocol»

blockquote>

А почему бы и нет? Поскольку ключевое слово weak имеет смысл только с ссылочными типами, к которым применяется ARC. ARC не относится к типам значений. И без указания нашего протокола с class мы не можем гарантировать, что наше свойство delegate будет присвоено ссылочному типу. (И если мы не используем weak, мы скорее всего создадим цикл сохранения.)

24
задан alex2k8 29 April 2009 в 18:01
поделиться

15 ответов

Забыв, что $ _ перезаписывается в блоках, я пару раз почесал голову в замешательстве, и аналогично для нескольких регулярных совпадений и массива $ match. .> & Л;

0
ответ дан kikuchiyo 16 October 2019 в 08:08
поделиться
# $x is not defined
[70]: $x -lt 0
True
[71]: [int]$x -eq 0
True

Итак, что такое $ x ..?

0
ответ дан stej 16 October 2019 в 08:08
поделиться

Это работает. Но почти наверняка не так, как вы думаете, это работает.

PS> $a = 42;
PS> [scriptblock]$b = { $a }
PS> & $b
42
0
ответ дан JaredPar 16 October 2019 в 08:08
поделиться

Еще один:

$x = 2
$y = 3
$a,$b = $x,$y*5 

из-за приоритета операторов в $ b нет 25; команда такая же, как ($ x, $ y) * 5, правильная версия -

$a,$b = $x,($y*5)
1
ответ дан stej 16 October 2019 в 08:08
поделиться
# The pipeline doesn't enumerate hashtables.
$ht = @{"foo" = 1; "bar" = 2}
$ht | measure

# Workaround: call GetEnumerator
$ht.GetEnumerator() | measure
7
ответ дан Richard Berg 16 October 2019 в 08:08
поделиться

Еще один забавный. Необработанное выражение по умолчанию записывает его в конвейер. Действительно раздражает, когда вы не понимаете, какая-то функция возвращает значение.

function example() {
  param ( $p1 ) {
  if ( $p1 ) {
    42
  }
  "done"
}

PS> example $true 
42
"done"
10
ответ дан JaredPar 16 October 2019 в 08:08
поделиться

My personal favorite is

function foo() {
  param ( $param1, $param2 = $(throw "Need a second parameter"))
  ...
}

foo (1,2)

For those unfamiliar with powershell that line throws because instead of passing 2 parameters it actually creates an array and passes one parameter. You have to call it as follows

foo 1 2
13
ответ дан 28 November 2019 в 22:40
поделиться

Вот что я недавно наткнулся на (PowerShell 2.0 CTP):

$items = "item0", "item1", "item2"

$part = ($items | select-string "item0")

$items = ($items | where {$part -notcontains $_})

Как вы думаете, что $ items будет в конце скрипта?

Я ожидал «item1» , "item2", но вместо этого значение $ items: "item0", "item1", "item2".

3
ответ дан 28 November 2019 в 22:40
поделиться
$files = Get-ChildItem . -inc *.extdoesntexist
foreach ($file in $files) {
    "$($file.Fullname.substring(2))"
}

Сбой с:

You cannot call a method on a null-valued expression.
At line:3 char:25
+ $file.Fullname.substring <<<< (2)

Исправьте это так:

$files = @(Get-ChildItem . -inc *.extdoesntexist)
foreach ($file in $files) {
    "$($file.Fullname.substring(2))"
}

Суть в том, что оператор foreach будет зацикливаться на скалярном значении, даже если это скалярное значение равно $ null. Когда Get-ChildItem в первом примере ничего не возвращает, $ files получает $ null. Если вы ожидаете, что команда вернет массив элементов, но есть вероятность, что она вернет только 1 элемент или ноль элементов, поместите @ () вокруг команды. Тогда вы всегда получите массив - будь то 0, 1 или N элементов. Примечание. Если элемент уже является массивом, размещение @ () не имеет никакого эффекта - он все равно будет тем же самым массивом (т. Е. Нет никакой дополнительной оболочки массива).

10
ответ дан 28 November 2019 в 22:40
поделиться

Еще одна проблема, с которой я столкнулся недавно: [строковые] параметры, принимающие ввод конвейера, на практике не являются строго типизированными. Вы можете перенаправить все что угодно, и PS принудит это через ToString ().

function Foo 
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, ValueFromPipeline=$True)]
        [string] $param
    )

    process { $param }
}

get-process svchost | Foo

К сожалению, нет способа отключить это. Лучший обходной путь, который я мог придумать:

function Bar
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, ValueFromPipeline=$True)]
        [object] $param
    )

    process 
    { 
        if ($param -isnot [string]) {
            throw "Pass a string you fool!"
        }
        # rest of function goes here
    }
}

edit - лучший обходной путь, который я начал использовать ...

Добавьте это в свой XML пользовательского типа -

<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>System.String</Name>
    <Members>
      <ScriptProperty>
        <Name>StringValue</Name>
        <GetScriptBlock>
          $this
        </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
</Types>

Затем напишите такие функции:

function Bar
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)]
        [Alias("StringValue")]
        [string] $param
    )

    process 
    { 
        # rest of function goes here
    }
}
0
ответ дан 28 November 2019 в 22:40
поделиться

Этот ранее меня уже сработал, используя $ o.SomeProperty, где он должен быть $ ($ o.SomeProperty).

0
ответ дан 28 November 2019 в 22:40
поделиться
6
ответ дан 28 November 2019 в 22:40
поделиться

Функции 'foo' и 'bar' выглядят эквивалентно.

function foo() { $null  }
function bar() { }

Например,

(foo) -eq $null
# True

(bar) -eq $null
# True

Но:

foo | %{ "foo" }
# Prints: foo

bar | %{ "bar" }
# PRINTS NOTHING

Возвращение $ null и ничего не возвращает не эквивалентно работе с трубами.


Это Один из них вдохновлен примером Кейта Хилла ...

function bar() {}

$list = @(foo)
$list.length
# Prints: 0

# Now let's try the same but with a temporal variable.
$tmp = foo
$list = @($tmp)
$list.length
# Prints: 1
2
ответ дан 28 November 2019 в 22:40
поделиться

alex2k8, я думаю, что ваш пример хорош для обсуждения:

# -----------------------------------
function foo($a){
    # I thought this is right.
    #if($a -eq $null)
    #{
    #    throw "You can't pass $null as argument."
    #}
    # But actually it should be:
    if($null -eq $a)
    {
        throw "You can't pass $null as argument." 
    }
}
foo @($null, $null)

PowerShell может использовать некоторые из компараторов для таких массивов, например:

$array -eq $value
## Returns all values in $array that equal $value

Исходя из этого, исходный пример возвращает два элемента (два значения $ null в массиве), которые оцениваются в $ true, поскольку в итоге получается коллекция из более чем одного элемента. Изменение порядка аргументов останавливает сравнение массивов.

Эта функция очень удобна в определенных ситуациях, но вам нужно знать об этом (как при обработке массива в PowerShell).

2
ответ дан 28 November 2019 в 22:40
поделиться

Для чтения и загрузки файлов из репозитория вы можете использовать любой веб-браузер. а из Subversion 1.6 даже можно увидеть другие ревизии, кроме HEAD. Однако вы не можете видеть сообщения журнала или наборы изменений, также вы не можете проверять или фиксировать файлы, однако я сомневаюсь, что веб-клиент является подходящим инструментом для этого.

Дополнение: Вы также можете использовать функциональность webDAV для записи непосредственно в файлы внутри вашего репозитория. (Автоматическая версия, подробности см. В svnbook )

Также существует множество svn-webclients, которые вы можете использовать в своем браузере. Вот два проекта: http://www.websvn.info/

Polarion WebClient для SVN также поддерживает добавление файлов и изменение с помощью цикла загрузки / выгрузки (не знаю для websvn) http://community.polarion.com /index.php?page=overview&project=svnwebclient<1215_121---4952587-

Допустим, у вас есть следующий XML-файл:

<Root>
    <Child />
    <Child />
</Root>

Запустите это:

PS > $myDoc = [xml](Get-Content $pathToMyDoc)
PS > @($myDoc.SelectNodes("/Root/Child")).Count
2
PS > @($myDoc.Root.Child).Count
2

Теперь отредактируйте XML-файл, чтобы он имел нет дочерних узлов, только корневой узел, и снова запустите эти операторы:

PS > $myDoc = [xml](Get-Content $pathToMyDoc)
PS > @($myDoc.SelectNodes("/Root/Child")).Count
0
PS > @($myDoc.Root.Child).Count
1

Этот 1 раздражает, когда вы хотите перебрать коллекцию узлов с помощью foreach тогда и только тогда, когда они действительно есть. Так я узнал, что нельзя использовать нотацию свойств (точек) обработчика XML в качестве простого ярлыка. Я считаю, что происходит то, что SelectNodes возвращает коллекцию 0. Когда @ 'ed, он преобразуется из XPathNodeList в Object [] (проверьте GetType ()), но длина сохранилась. Динамически созданное свойство $ myDoc.Root.Child (которое по существу не существует) возвращает $ null. Когда $ null равен @ 'ed, он становится массивом длины 1.

3
ответ дан 28 November 2019 в 22:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: