Суть ответа Starscream верна, но он пропускает , почему , который, как мне кажется, важен здесь. Это сводится к ARC и управлению памятью.
Swift - это язык ссылочных типов и типов значений. Классы являются ссылочными типами, а все остальное - типом значения. Фактически мы на самом деле не указываем, что протокол наследует от class
... это больше похоже на то, что мы указываем, что протокол может быть реализован только с помощью ссылочных типов .
И почему это важно?
Это важно, потому что без него мы не сможем использовать ключевое слово weak
с протоколом.
protocol ExampleProtocol {}
class DelegatedClass {
weak var delegate: ExampleProtocol?
}
Это порождает ошибку:
«слабый» не может применяться к неклассовому типу «ExampleProtocol»
blockquote>А почему бы и нет? Поскольку ключевое слово
weak
имеет смысл только с ссылочными типами, к которым применяется ARC. ARC не относится к типам значений. И без указания нашего протокола сclass
мы не можем гарантировать, что наше свойствоdelegate
будет присвоено ссылочному типу. (И если мы не используемweak
, мы скорее всего создадим цикл сохранения.)
Забыв, что $ _ перезаписывается в блоках, я пару раз почесал голову в замешательстве, и аналогично для нескольких регулярных совпадений и массива $ match. .> & Л;
# $x is not defined
[70]: $x -lt 0
True
[71]: [int]$x -eq 0
True
Итак, что такое $ x ..?
Это работает. Но почти наверняка не так, как вы думаете, это работает.
PS> $a = 42;
PS> [scriptblock]$b = { $a }
PS> & $b
42
Еще один:
$x = 2
$y = 3
$a,$b = $x,$y*5
из-за приоритета операторов в $ b нет 25; команда такая же, как ($ x, $ y) * 5, правильная версия -
$a,$b = $x,($y*5)
# The pipeline doesn't enumerate hashtables.
$ht = @{"foo" = 1; "bar" = 2}
$ht | measure
# Workaround: call GetEnumerator
$ht.GetEnumerator() | measure
Еще один забавный. Необработанное выражение по умолчанию записывает его в конвейер. Действительно раздражает, когда вы не понимаете, какая-то функция возвращает значение.
function example() {
param ( $p1 ) {
if ( $p1 ) {
42
}
"done"
}
PS> example $true
42
"done"
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
Вот что я недавно наткнулся на (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".
$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 элементов. Примечание. Если элемент уже является массивом, размещение @ ()
не имеет никакого эффекта - он все равно будет тем же самым массивом (т. Е. Нет никакой дополнительной оболочки массива).
Еще одна проблема, с которой я столкнулся недавно: [строковые] параметры, принимающие ввод конвейера, на практике не являются строго типизированными. Вы можете перенаправить все что угодно, и 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
}
}
Этот ранее меня уже сработал, используя $ o.SomeProperty, где он должен быть $ ($ o.SomeProperty).
Функции '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
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).
Для чтения и загрузки файлов из репозитория вы можете использовать любой веб-браузер. а из 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-файл: Запустите это: Теперь отредактируйте XML-файл, чтобы он имел нет дочерних узлов, только корневой узел, и снова запустите эти операторы: Этот 1 раздражает, когда вы хотите перебрать коллекцию узлов с помощью foreach тогда и только тогда, когда они действительно есть. Так я узнал, что нельзя использовать нотацию свойств (точек) обработчика XML в качестве простого ярлыка. Я считаю, что происходит то, что SelectNodes возвращает коллекцию 0. Когда @ 'ed, он преобразуется из XPathNodeList в Object [] (проверьте GetType ()), но длина сохранилась. Динамически созданное свойство $ myDoc.Root.Child (которое по существу не существует) возвращает $ null. Когда $ null равен @ 'ed, он становится массивом длины 1. <Root>
<Child />
<Child />
</Root>
PS > $myDoc = [xml](Get-Content $pathToMyDoc)
PS > @($myDoc.SelectNodes("/Root/Child")).Count
2
PS > @($myDoc.Root.Child).Count
2
PS > $myDoc = [xml](Get-Content $pathToMyDoc)
PS > @($myDoc.SelectNodes("/Root/Child")).Count
0
PS > @($myDoc.Root.Child).Count
1