Como escrever código com a linguagem Swift

Para quem quer começar a programar com a linguagem Swift, esse artigo fornecerá uma introdução rápida aos conceitos e recursos mais importantes da linguagem.

Instalando Swift

O primeiro passo para usar Swift é baixar e instalar o compilador e outros componentes necessários. Vá para a página de Download e siga as instruções para a sua plataforma.
Para poder seguir com o exemplos abaixo, certifique-se de adicionar o Swift ao seu $PATH.

No macOS

A localização padrão do pacote que você baixou no macOS é o /Library/Developer/Toolchains. Você pode fazer com que as ferramentas fiquem disponíveis para uso no terminal com o seguinte comando:

$ export PATH=/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin:"${PATH}"

No Linux

Em primeiro lugar, instale o clang:

$ sudo apt-get install clang

Se você instalou o pacote do Swift em algum outro diretório que não fosse a raiz do sistema, irá precisar executar o seguinte comando, usando caminho de sua instalação do Swift:

$ export PATH=/path/to/Swift/usr/bin:"${PATH}"

Você pode verificar que esta usando a versão esperado do Swift digitando o comando swift e passando como parâmetro a flag –version:

$ swift --version
Apple Swift version 2.2-dev (LLVM ..., Clang ..., Swift ...)

O sufixo -dev no número da versão é usado para indicar que se tratado de uma versão de desenvolvimento, não uma versão de lançamento.

Usando a REPL

Se você executar o comando swift sem nenhum argumento, você executará o REPL, um shell interativo que irá ler, processar e imprimir  o resultado que qualquer código Swift que você digitar:

$ swift
Welcome to Apple Swift version 2.2. Type :help for assistance.
  1>

Interagir com o REPL é uma ótima forma de experimentar com o Swift. Por exemplo, se você digitar a expressão 1 + 2, o resultado da expressão, 3, é impresso na linha seguinte:

  1> 1 + 2
$R0: Int = 3

Você pode associar valores para constantes e variáveis, e usa-las em linhas subsequentes. Por exemplo, o valor String “Hello, world!” pode ser associado à contante greeting, e então passada como argumento para a função print(_:).

  2> let greeting = "Hello!"
greeting: String = "Hello!"
  3> print(greeting)
Hello!

Se você digitar uma expressão inválida, o REPL irá exibir um erro mostrando onde o problema ocorreu:

let answer = "forty"-"two"
error: binary operator '-' cannot be applied to two 'String' operands
let answer = "forty"-"two"
             ~~~~~~~^~~~~~

Você pode usar seta-pra-cima ou seta-pra-baixo para mover-se pelas linhas digitadas no REPL. Isso permite que você faça pequenas alterações em uma expressão anterior sem ter que redigitar a linha inteira, e isso é especialmente conveniente para corrigir error como o do exemplo anterior:

let answer = "forty-two"
answer: String = "forty-two"

Um outro recursos útil do REPL é que ele pode sugerir automaticamente funções e método que pode ser usado em um contexto em particular. Por exemplo, se você digitar re depois que o operador ponto em um valor String e apertar a tecla TAB, o REPL irá lhe fornecer uma lista de sugestões disponíveis como remove(at:) replaceSubrange(bounds:with:):

5> "Hi!".re⇥
Available completions:
	remove(at: Index) -> Character
	removeAll() -> Void
	removeAll(keepingCapacity: Bool) -> Void
	removeSubrange(bounds: ClosedRange<Index>) -> Void
	removeSubrange(bounds: Range<Index>) -> Void
	replaceSubrange(bounds: ClosedRange<Index>, with: C) -> Void
	replaceSubrange(bounds: ClosedRange<Index>, with: String) -> Void
	replaceSubrange(bounds: Range<Index>, with: C) -> Void
	replaceSubrange(bounds: Range<Index>, with: String) -> Void
	reserveCapacity(n: Int) -> Void

Se você iniciar um bloco de código, como quando iterando um array em um loop for-in, o REPL irá automaticamente identar a linha seguinte, e irá alterar o prompt de > para um ponto para indicar que o código digitado nessa linha irá ser executado apenas quando o bloco inteiro for processado.

  6> let numbers = [1,2,3]
numbers: [Int] = 3 values {
  [0] = 1
  [1] = 2
  [2] = 3
}
  7> for n in numbers.reversed() {
  8.     print(n)
  9. }
3
2
1

Todas as funcionalidades do Swift estão disponíveis para você no REPL, da criação de sentenças de controle de fluxo à declaração de estruturas e classes.
Você também pode importar módulos do sistema, como o Darwin no macOS ou a Glibc no linux:

No macOS

1> import Darwin
2> arc4random_uniform(10)
$R0: UInt32 = 4

No Linux

1> import Glibc
2> random() % 10
$R0: Int32 = 4

Usando o Gerenciador de pacotes

O gerenciados de pacotes do Swift fornece um sistema convencional para criar bibliotecas e executáveis, e compartilhar código entre projetos diferentes.
Esses exemplo assumem que você tenha adicionado o swift em seu PATH; veja a seção de Instalação para mais informações. Uma vez que esteja disponível, você pode invocar as ferramentas do gerenciador de pacotes: swift packageswift buildswift test.

$ swift package --help
OVERVIEW: Perform operations on Swift packages
...

Criando um pacote

Para criar um novo pacote Swift. crie um novo diretório chamado Hello:

$ mkdir Hello
$ cd Hello

Todo pacote precisa ter um arquivo de manifesto chamado Package.swift em seu diretório raiz. Você pode criar um pacote minimo usando:

$ swift package init

Por padrão, o comando init irá criar um pacote com a seguinte estrutura:

├── Package.swift
├── Sources
│   └── Hello.swift
└── Tests
    ├── HelloTests
    │   └── HelloTests.swift
    └── LinuxMain.swift

Você pode usar swift build para compilar o pacote. Isso irá baixar, determinar e compilar as dependências mencionadas no arquivo de manifesto Package.swift.

$ swift build
Compile Swift Module 'Hello' (1 sources)

Para executar testes em um pacote, use: swift test

$ swift test
Compile Swift Module 'HelloTests' (1 sources)
Linking ./.build/debug/HelloPackageTests.xctest/Contents/MacOS/HelloPackageTests
Test Suite 'All tests' started at 2016-08-29 08:00:31.453
Test Suite 'HelloPackageTests.xctest' started at 2016-08-29 08:00:31.454
Test Suite 'HelloTests' started at 2016-08-29 08:00:31.454
Test Case '-[HelloTests.HelloTests testExample]' started.
Test Case '-[HelloTests.HelloTests testExample]' passed (0.001 seconds).
Test Suite 'HelloTests' passed at 2016-08-29 08:00:31.455.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'HelloPackageTests.xctest' passed at 2016-08-29 08:00:31.455.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'All tests' passed at 2016-08-29 08:00:31.455.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.002) seconds

Criando um executável

Um pacote é considerado como um executável se possuir um arquivo chamado main.swift. O gerenciados de pacote irá compilar esse arquivo em um binário executável.
No nosso exemplo, o pacote produzirá um executável chamado Hello que produzirá a saída “Hello, world!”.
Em primeiro lugar crie um diretório chamado Hello:

$ mkdir Hello
$ cd Hello

Agora execute o comando init com o tipo executable:

$ swift package init --type executable

Compile o pacote executando o comando swift build:

$ swift build

Depois que o comando for finalizado, o resultado da compilação estará disponível no diretório .build. Execute o programa Hello com o seguinte comando:

$ .build/debug/Hello
Hello, world!

No próximo passo vamos definir uma nova função sayHello(name:) em um novo arquivo de código, e fazer com que o executável chame essa função ao invés de chamar diretamente print(_:).

Trabalhando com múltiplos arquivos de código

Crie um novo arquivo no diretório Sources/ com o nome Greeter.swift, e digite nele o seguinte código:

func sayHello(name: String) {
    print("Hello, \(name)!")
}

A função sayHello(name:) recebe um único argumento do tipo String e imprime a nossa mensagem “Hello” de antes, substituindo a palavra “world” pelo nosso argumento.
Agora abra o arquivo main.swift novamente, e substitua o código existente pelo código seguinte:

if CommandLine.arguments.count != 2 {
    print("Usage: hello NAME")
} else {
    let name = CommandLine.arguments[1]
    sayHello(name: name)
}

Ao invés de usar um nome definido no código como antes, main.swift agora lê os argumentos passados pela linha de comando. E ao invés de invocar diretamente  print(_:), main.swift agora chama o método sayHello(name:). Como o método é parte do módulo Hello, nenhuma sentença import é necesária.
Execute swift build and e teste a nova versão de Hello:

$ swift build
$ .build/debug/Hello `whoami`

Para aprender mais sobre o Gerenciador de pacotes do Swift, incluindo como compilar módulos, importar dependências e mapear bibliotecas do sistema, veja o artigo Swift Package Manager no site oficial.

Usando o depurador LLDB

Você pode usar o depurador LLDB para executar programas Swift passo a passo, configurar breakpoints e inspecionar e modificar o estado do programa.
Como exemplo, considere o seguinte código, que define uma função factorial(n:), e imprime o resultado da chamada a essa função:

func factorial(n: Int) -> Int {
    if n <= 1 { return n }
    return n * factorial(n: n - 1)
}
let number = 4
print("\(number)! is equal to \(factorial(n: number))")

Crie um arquivo com o nome Factorial.swift com o código acima,  e execute o comando swiftc, passando como argumento o nome do arquivo, junto com a opção -g para gerar as informações de depuração. Isso irá criar um executável chamado Factorial no diretório atual.

$ swiftc -g Factorial.swift
$ ls
Factorial.dSYM
Factorial.swift
Factorial*

Ao invés de executar o programa Factorial diretamente, execute-o através do depurador LLDB informado ele como argumento para o comando lldb.

$ lldb Factorial
(lldb) target create "Factorial"
Current executable set to 'Factorial' (x86_64).

Isso irá iniciar um console interativo que permite que você execute comando do LLDB.

Para mais informações sobre o LLDB, veja o LLDB Tutorial.

Configure um breakpoint na linha2 da função factorial(n:) com o comando breakpoint set (b), para que o processo seja interrompido a cada vez que a função seja executada.

(lldb) b 2
Breakpoint 1: where = Factorial`Factorial.factorial (Swift.Int) -> Swift.Int + 12 at Factorial.swift:2, address = 0x0000000100000e7c

Execute o processo com o comando run (r).O processo irá ser interrompido quando a função factorial(n:) é chamada.

(lldb) r
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14dfdf, 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2
   1    func factorial(n: Int) -> Int {
-> 2        if n <= 1 { return n }
   3        return n * factorial(n: n - 1)
   4    }
   5
   6    let number = 4
   7    print("\(number)! is equal to \(factorial(n: number))")

Use o comando print (p) para inspecionar o valor do parâmetro n.

(lldb) p n
(Int) $R0 = 4

O comando print pode executar expressões Swift também.

(lldb) p n * n
(Int) $R1 = 16

Use o comando backtrace (bt) para exibir os frames que levaram à invocação da função factorial(n:).

(lldb) bt
* thread #1: tid = 0x14e393, 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2
    frame #1: 0x0000000100000daf Factorial`main + 287 at Factorial.swift:7
    frame #2: 0x00007fff890be5ad libdyld.dylib`start + 1
    frame #3: 0x00007fff890be5ad libdyld.dylib`start + 1

Use o comando continue (c) para continuar o processo até que o breakpoint seja encontrado novamente.

(lldb) c
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14e393, 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2
   1    func factorial(n: Int) -> Int {
-> 2        if n <= 1 { return n }
   3        return n * factorial(n: n - 1)
   4    }
   5
   6    let number = 4
   7    print("\(number)! is equal to \(factorial(n: number))")

Use o comando print (p) novamente para inspecionar o valor do parâmetro n na segunda chamada à função factorial(n:).

(lldb) p n
(Int) $R2 = 3

Use o comando breakpoint disable (br di) para remover todos os breakpoints e o comando continue(c) para que o processo seja executado até o fim, sem mais interrupções.

(lldb) br di
All breakpoints disabled. (1 breakpoints)
(lldb) c
Process 40246 resuming
4! is equal to 24
Process 40246 exited with status = 0 (0x00000000)

Agora que você foi introduzido ao REPL, sistema de compilação e depurador, seguem algumas sugestões para você seguir: