Funções

As funções são pedaços de código independentes que executam uma tarefa específica. Você atribui a uma função um nome que identifica o que faz, e este nome é usado para "chamar" a função para executar sua tarefa quando necessário.

A sintaxe unificada da função no Swift é flexível o suficiente para expressar qualquer coisa desde uma função simples no estilo C sem nomes de parâmetros até um método complexo no estilo Objective-C com nomes e apelidos de argumentos para cada parâmetro. Os parâmetros podem fornecer valores padrão para simplificar as chamadas de função e podem ser passados ​​como parâmetros in-out, que modificam uma variável passada uma vez que a função concluiu sua execução.

Todas as funções no Swift têm um tipo, consistindo nos tipos dos parâmetros da função e no tipo de retorno. Você pode usar esse tipo como qualquer outro tipo no Swift, o que facilita a passagem de funções como parâmetros para outras funções e para retornar as funções das funções. Elas também podem ser escritas dentro de outras funções para encapsular funcionalidades úteis dentro de um escopo de função aninhada.

Definindo e Chamando Funcões

Quando você define uma função, você pode opcionalmente definir um ou mais valores digitados e nomeados que a função toma como entrada, conhecidos como parâmetros. Você também pode opcionalmente definir um tipo de valor que a função irá retornar como saída quando terminar seu processamento, conhecido como seu tipo de retorno.

Cada função possui um nome da função, que descreve a tarefa que a função executará. Para usar uma função, você "chama" essa função com seu nome e passa os valores de entrada (conhecidos como argumentos) que correspondem aos tipos de parâmetros da função. Os argumentos de uma função sempre devem ser fornecidos na mesma ordem que a lista de parâmetros da função.

A função no exemplo abaixo é chamada de greet(person :), porque é o que ela faz, pega o nome de uma pessoa como entrada e retorna uma saudação (greet em inglês) para essa pessoa. Para fazer isso, você define um parâmetro de entrada - um valor String chamado person - e um tipo de retorno String, que conterá uma saudação para essa pessoa:

Toda essa informação é envolvida na definição da função, que é prefixada com o comando func. Você indica o tipo de retorno da função com a seta de retorno -> (um hífen seguido por um sinal de maior), que é seguido pelo nome do tipo a retornar.

A definição descreve o que a função faz, o que espera receber e o que ela retorna quando termina. A definição facilita que a função seja chamada de forma indevida no seu código:

Você pode chamar a função greet(person:) passando um valor do tipo String depois do apelido do parâmetro person, como por exemplo greet(person: "Anna"). Como a função retorna uma string, greet(person:) pode ser usado em uma função print(_:separator:terminator:) para imprimir essa string e ver o seu valor retornado como mostrado acima.

Nota

A função print(_:separator:terminator:) não tem um apelido para seu primeiro parâmetro, e os seus outros argumentos são opcionais pois contem um valor default internamente. Essas variações na sintaxe das funções são discutidas na seção Apelidos para parâmetros de funções e Valores padrão para parâmetros.

O corpo da função greet(person:) começa definindo uma nova constante do tipo String chamada greeting e setando ela para uma mensagem de saudação simples. Esta constante é então passada de volta para fora da função usando o comando return. Na linha de código que diz return greeting, a função termina sua execução e retorna o valor atual de greeting.

Você pode chamar a função greet(person:) várias vezes com diferentes valores de entrada. O exemplo acima mostra o que acontece se for chamado com um valor de entrada de "Anna" e um valor de entrada de "Brian". A função retorna uma saudação personalizada em cada caso.

Para tornar o corpo desta função mais curto, você pode combinar a criação da mensagem e a declaração de retorno em uma linha:

Parâmetros de Função e Valores de Retorno

Os parâmetros de uma função e os valores de retorno são extremamente flexíveis no Swift. Você pode definir qualquer coisa, desde uma função de utilidade simples com um único parâmetro sem nome até uma função complexa com números expressívos de parâmetros e diferentes opções de parâmetros.

Funções sem parâmetros

Funções não são obrigadas a ter parâmetros definidos. Aqui temos uma função sem parâmetros de entrada, que sempre retorna a mesma mensagem em string que se chama:

A definição da função ainda precisa dos parenteses depois do seu nome, mesmo se ela não recebe nenhum parâmetro. Também devemos usar o par de parenteses depois do nome da função quando chamamos a mesma.

Funções com multiplos parâmetros

Funções podem ter vários parâmetros, que são escritos dentro dos parenteses da função separados por vírgulas. A função abaixo recebe o nome de uma pessoa e se ele já recebeu uma saudação e retorna uma saudação apropriada para aquela pessoa:

Você deve chamar a função greet(person: alreadyGreeted:) passando um valor do tipo String para o argumento person e um valor do tipo Bool para o argumento alreadyGreeted dentro dos parenteses, separados por vírgulas. Note que essa função é diferente da função greet(person:) mostrada anteriormente. Mesmo que ambas as funções tenham o nome igual (greet) a função greet(person: alreadyGreeted:) recebe dois parâmetros enquanto a função greet(person:) recebe somente um.

Funções sem valores de retorno

Funções não são obrigadas a definir um tipo de retorno. Aqui está a versão da função greet(person:) que imprimi o valor da sua própria String ao invés de retorná-la.

Como ela não precisa de nenhum tipo de retorno, a definição da função não inclui a flecha de retorno (->) e o tipo de retorno.

Nota

Estritamente falando, essa versão da função greet(person:) ainda retorna um valor mesmo que ela não tenha um tipo de retorno definido. Funções sem um tipo de retorno definido retornam um valor especial do tipo Void. Esse valor é simplesmente uma tupla vazia, escrita como ().

O valor de retorno de uma função pode ser ignorado quando ela é chamada:

A primeira função printAndCount(string:) imprimi uma string e retorna a contagem de caracteres como um Int. A segunda função printWithoutCounting(string:) chama a primeira função mas ignora seu valor. Quando a segunda função é chamada, a mensagem ainda é impressa pela primeira função, mas o valor retornado por ela não é usado.

Nota

Valores retornados podem ser ignorados, mas a função que diz que retorna um valor sempre deve fazer isso. Uma função que define um tipo de retorno não pode terminar sua execução sem retornar um valor, a tentativa de fazer isso resulta em um erro em tempo de compilação.

Funções com multiplos valores de retorno

Você pode usar uma tupla como tipo de retorno para uma função retornar multiplos valores como parte de um único valor composto. O exemplo abaixo define uma função chamada minMax(array:) que encontra o maior valor e o menor em um array de valores do tipo Int:

A função minMax(array:) retorna uma tupla contendo dois valores do tipo Int. Esses valores são nomeados como min e max para que possam ser acessados pelos nomes quando a função estiver retornando os valores.

O corpo da função minMax(array:) começa criando duas variáveis chamadas currentMin e currentMax e setando os primeiros valores para a posição 0 do array recebido como parâmetro. A função então itera sobre os items no array e verifica se cada valor é maior ou menor que os valores de currentMin e currentMax respectivamente. Por fim os valores mínimos e máximos são retornados como uma tupla com dois valores do tipo Int.

Como os valores da tupla são nomeados como parte o tipo de retorno da função, eles podem ser acessados através da sintaxe de ponto para usar os valores de min e max:

Note que os membros da tupla não precisam ser nomeados no momento em que função retorna essa tupla, pois os nomes já são definidos na assinatura da função como o tipo de retorno.

Tuplas opcionais como tipo de retorno

Se a tupla a ser retornada de uma função tem o potencial de não ter valor nenhum para a tupla inteira, você pode usar uma tupla opcional como tipo de retorno para refletir o fato de que a tupla inteira pode ser nula (nil). Você pode escrever uma tupla opcional como tipo de retorno colocando um ponto de interrogação depois dos parenteses que fecham a tupla, como (Int, Int)? ou (String, Int, Bool)?.

Nota

Uma tupla opcional, como (Int, Int)? é diferente de uma tupla que contém valores opcionais, como (Int?, Int?). A primeira variação indica que a tupla inteira é opcional, não só cada valor individual dentro dela como na segunda variação.

A função acima minMax(array:) retorna uma tupla contendo dois valores do tipo Int. Entretanto a função não executa nenhuma validação se o array passado como parâmetro é um array válido. Se o parâmetro array armazenar um array vazio,a função minMax(array:) definida acima irá disparar um erro em tempo de execução quando tentar acessar a posição 0 como array[0].

Para tratar um array vazio de forma segura, escreva a função minMax(array:) com um uma tupla opcional e retorne o valor nil quando o array estiver vazio:

Você pode usar o recurso de binding opcional para verificar se essa versão da função retorna um valor válido ou nil:

Apelidos de argumentos e nomes de parâmetros em funções

Cada parâmetro de uma função possui ambos, um apelido de argumento e um nome do parâmetro. O apelido de argumento é usado quando chamamos a função, cada argumento é fornecido na chamada da função depois do seu apelido, já o nome do parâmetro é usado na implementação da função. Por padrão, os parâmetros usam seu nome como apelido de argumento.

Todos os parâmetros de uma função devem ter nomes únicos, porém é possível que multiplos parâmetros tenham o mesmo apelido de argumento, mas deixá-los únicos deixa o seu código mais legível.

Especificando apelidos de argumentos

Você pode escrever um apelido de argumento antes do nome do parâmetro, separado por um espaço:

Aqui temos uma variação da função greet(person:) que recebe o nome da pessoa e a cidade em que nasceu para retornar a saudação:

O uso de um apelido de argumento permite que uma função seja chamada de uma forma mais expressiva e significativa, enquanto ainda provê o corpo da função de forma legível e claro.

Escondendo apelidos de argumentos

Se você não quiser um apelido de argumento para um parâmetro, escreva um underscore _ no lugar do apelido do argumento para aquele parâmetro

Se um parâmetro tem um apelido de argumento, o argumento deve ser nomeado quando a função for chamada.

Valores padrão de parâmetros

Você pode definir um valor padrão para qualquer parâmetro em uma função setando um valor para o parâmetro depois do seu tipo. Se um valor padrão for definido, você pode omitir esse parâmetro quando chamar a função.

Coloque os parâmetros que não tem valores padrão no começo da lista de parâmetros da função, antes dos parâmetros que tem valores default. Paramêtros que não tem valores default são mais importantes para o objetivo da função, portanto ao escrever eles primeiro torna mais fácil de reconhecer que a mesma funcão está sendo chamada independentemente se algum parâmetro que tenha um valor padrão esteja omitido.

Parâmetros Variadic

Um parâmetro variadic aceita zero ou mais valores de um tipo específico. Você pode usar parâmetros variadic para especificar que o parâmetro pode ser passado com um número variante de dados quando a função é chamada. Você pode escrever parâmetros variadic inserindo 3 pontos ... depois do tipo do parâmetro.

O valor passado para um parâmetro variadic ficam disponíveis dentro do corpo da função como um array do tipo apropriado. Por exemplo, um parâmetro variadic com o nome numbers e o tipo Double... se torna disponível dentro do corpo da função como uma constante do tipo Array<Double>.

O Exemplo abaixo calcula a média aritmética de uma lista de números de qualquer tamanho:

Nota

Uma função pode ter no máximo 1 parâmetro variadic.

Parâmetros In-Out

Parâmetros de funções são constantes por padrão e tentar mudar o valor de um parâmetro dentro do corpo da função resulta em um erro em tempo de compilação, o que significa que você não pode mudar o valor de um parâmetro por engano. Se você precisa que uma função modifique o valor de um parâmetro, defina ele como um parâmetro in-out.

Você pode escrever um parâmetro in-out colocando o comando inout antes do tipo do parâmetro. Um parâmetro in-out tem um valor que é passado para dentro da função, modificado por ela e então retornado para fora da função para substituir o valor original. Para uma discussão detalhada sobre o comportamento dos parâmetros inout e a otimização dos compiladores associados a eles, veja a a seção Parâmetros In-Out na Referência de Linguagem.

Você pode passar somente variáveis como argumentos para um parâmetro in-out, você não pode passar uma constante ou um valor literal como argumento porque constantes e valores literais não podem ser modificados. Você deve colocar o simbolo & diretamente antes do nome da variável quando voce estiver passando ela como argumento para um parâmentro in-out para indicar que ele pode ser modificado pela função.

Nota

Parâmetros in-out não podem ter valores padrão, e parâmetros variadic não podem ser marcados como inout.

Aqui está um exemplo de uma funcão chamada swapTwoInts(a: b:) que tem dois parâmetros do tipo Int como in-out chamados de a e b:

A função swapTwoInts(a: b:) simplesmente troca o valor de b para a e o valor de a para b. A função executa essa troca armazenando o valor de a em uma constante temporaria chamada temporaryA, e setando o valor de b para a e para finalizar o valor de temporaryA para b.

Você pode chamar a função swapTwoInts(a: b:) com duas variáveis do tipo Int para trocar seus valores. Note que os nomes someInt e anotherInt contém o simbolo & quando são passados para a função swapTwoInts(a: b:):

O exemplo acima mostra que os valores originais de someInt e anotherInt são modificados pela função swapTwoInts(a: b:), mesmo que eles sejam definidos fora da função.

Nota

Parâmetros do tipo in-out não são a mesma coisa que retornar valores de uma função. A função swapTwoInts(a: b:) não define um tipo de retorno e nem retorna um valor, mas mesmo assim continua a modificar os valores de someInt e anotherInt. Parâmetros in-out são uma alternativa para uma função ter efeito fora do escopo do seu corpo.

Tipos de Funções

Toda função tem um tipo específico, feito através dos tipos dos parâmetro e do tipo de retorno da função. Por exemplo:

Este exemplo define duas simples funções matemáticas chamadas addTwoInts e multiplyTwoInts. Cada uma dessas funções recebe dois valores do tipo Int como parâmetro e retornam um valor do tipo Int, que é o resultado da operação matemática apropriada para cada uma.

O tipo e cada uma dessas funções é (Int, Int) -> Int, que pode ser lido como: "Uma função que recebe dois parâmetros do tipo Int e retorna um valor do tipo Int".

Aqui está outro exemplo, agora de uma função que não recebe parâmetros e não retorna valores:

O tipo dessa função é () -> Void, ou, "Uma função que não recebe parâmetros e retorna Void."

Usando tipos de funções

Você pode usar os tipos de funções como qualquer outro tipo no Swift, por exemplo, você pode definir uma constante ou variável para ser do tipo de uma função e setar uma função apropriada para ela.

O exemplo acima pode ser lido como: "Defina uma variável chamada mathFunction, que tem o tipo de uma função que recebe dois parâmetros do tipo Int e retorna um valor do tipo Int, depois atribua para essa variável referenciar a função chamada addTwoInts.

A função addTwoInts(a: b:) tem o mesmo tipo que a variável mathFunction, e portanto, a atribuição é permitida pelo type-checker do Swift.

Agora você pode chamar a função atribuida para a variável mathFunction normalmente:

Uma função diferente com o mesmo tipo pode ser atribuida para a mesma variável, do mesmo jeito que tipos que não são funções.

Assim como qualquer outro tipo, você pode deixar que o Swift descubra o tipo da função quando você atribui uma função para uma constante ou variável.

Tipos de funções como tipos de parâmetros

Você pode usar um tipo de uma função, como (Int, Int) -> Int como um tipo de parâmetro para outra função. Isso permite você deixar alguns aspectos da implementação da função para quem chamar a função fornecer.

Aqui temos um exemplo que imprime o resultado das operações matemáticas acima:

Este exemplo define uma função chamada printMathResult(mathFunction: a: b: ) que recebe três parâmetros. O primeiro parâmetro é chamado de mathFunction e o seu tipo é (Int, Int) -> Int. Você pode passar qualquer função desse tipo como argumento para o primeiro parâmetro. O segundo e terceiro parâmetros são chamados de a e b, ambos são do tipo Int e são usados como valores de entrada para a função matemática.

Quando a funçãoprintMathResult(mathFunction: a: b:) é chamada, é passado a função addTwoInts(a: b:) e os valores inteiros 3 e 5, ela então chama a função fornecida como argumento com os valores 3 e 5 e por final imprime o resultado 8.

O papel principal da função printMathResult(mathFunction: a: b:) é imprimir o resultado de uma chamada para a função matemática do tipo específico. Não importa o que a implementação da função faz, só importa que o tipo da função seja correto. Isso permite que a função printMathResult(mathFunction: a: b:) distribua algumas das suas funcionalidades para quem chamar a função de forma segura.

Tipos de funções como tipos de retorno

Você pode usar um tipo de uma função como tipo de retorno de outra função. Para fazer isso escreva o tipo de uma função depois do operador de retorno -> da função.

O próximo exemplo define duas funções simples chamadas stepForward(input : ) e setBackward(input :). A primeira função retorna o seu valor de input mais um, já a segunda função retorna retorna o valor de input menos um. Ambas as funções são do tipo (Int) -> Int:

Abaixo temos uma função chamada chooseStepFunction(backward:) no qual o tipo do seu retorno é (Int) -> Int. Ela retorna a função stepForward(input:) ou a função stepBackward(input:) baseado no parâmetro booleano chamado backward:

Agora você pode usar a função chooseStepFunction(backward:) para obter a função que vai mover em uma direção ou outra:

O exemplo acima determina se um passo positivo ou negativo é necessário para mover uma variável chamada currentValue progressivamente até chegar á zero. currentValue tem um valor inicial de 3, o que quer dizer que a expressãocurrentValue > 0returna true, o que faz com que a função chooseStepFunction(backward:) retorne a função stepBack(input:). Uma referência para a função retornada é armazenada em uma constante chamada moveNearerToZero.

Agora que a constante moveNearerToZero faz referência a função correta, ela pode ser usada pra contar até zero:

Funções Aninhadas

Todas as funções que você encontrou até agora neste capítulo foram exemplos de funções globais, que são definidas em um escopo global. Você também pode definir funções dentro do corpo de outras funções, conhecidas como funções aninhadas.

Funções aninhadas ficam escondidas do seu escopo de fora por padrão, mas ainda podem ser chamadas e usadas pela função que está englobada. Uma função que engloba outra também pode retornar uma das suas funções aninhadas para permitir que essa função seja usada em outro escopo.

Você pode reescrever a função chooseStepFunction(backward:) para usar e retornar funções aninhadas:

results matching ""

    No results matching ""