Skip to content

Latest commit

 

History

History
479 lines (352 loc) · 12.9 KB

File metadata and controls

479 lines (352 loc) · 12.9 KB

Função

Uma função é um grupo de instruções que existem dentro de um programa com a finalidade de executar uma tarefa específica. Em um alto nível, uma função recebe uma entrada e retorna uma saída.

Funções são geralmente o bloco de códigos ou instruções em um programa que dá ao usuário a capacidade de reutilizar o mesmo código que, em última análise, economiza o uso excessivo de memória, atua como uma economia de tempo e, mais importante, fornece melhor legibilidade do código. Então, basicamente, uma função é uma coleção de instruções que executam alguma tarefa específica e retornam o resultado para o chamador. Uma função também pode executar alguma tarefa específica sem retornar nada.

Abaixo o exemplo de sintaxe de função em Go:

func nome_funcao(lista_parametros)(tipo_retorno){
    // corpo da função.....
}

A declaração da função contém:

  • func: É uma palavra-chave na linguagem Go, que é usada para criar uma função.
  • nome_funcao: É o nome da função.
  • lista_parametros: Ele contém o nome e o tipo dos parâmetros de função.
  • tipo_retorno: É opcional e contém os tipos dos valores que a função retorna. Se você estiver usando tipo_retorno em sua função, então é necessário usar uma instrução return em sua função.

A Invocação de Função ou a Chamada de Função é feita quando o usuário deseja executar a função. A função precisa ser chamada para usar sua funcionalidade. Como mostrado no exemplo abaixo, temos uma função chamada area() com dois parâmetros. Agora chamamos essa função na função principal usando seu nome, ou seja, area(12, 10) com dois parâmetros.

package main
import "fmt"
 
func area(length, width int)int{
     
    Ar := length * width
    return Ar
}

func main() {
   fmt.Printf("Area of rectangle is : %d", area(12, 10))
}

// Saída:
// Area of rectangle is : 120

Note Se as funções com nomes que começam com uma letra maiúscula serão exportadas para outros pacotes. Se o nome da função começar com uma letra minúscula, ela não será exportada para outros pacotes, mas você poderá chamar essa função dentro do mesmo pacote.

Retornos

Golang permite que você nomeie os valores de retorno de uma função. Também podemos nomear o valor de retorno definindo variáveis. Neste caso não é necessário retornar a variável declarada no retorno. Veja o exemplo abaixo:

package main

import "fmt"

func rectangle(l int, b int) (area int) {
    var parameter int
    parameter = 2 * (l + b)
    fmt.Println("Parameter: ", parameter)

    area = l * b
    return // Return statement without specify variable name
}

func main() {
    fmt.Println("Area: ", rectangle(20, 30))
}

// Saída:
// Parameter:  100
// Area:  600

Argumentos

Na linguagem Go, os parâmetros passados para uma função são chamados de parâmetros reais, enquanto os parâmetros recebidos por uma função são chamados de parâmetros formais.

A linguagem Go oferece suporte a duas maneiras de passar argumentos para sua função:

  • Chamada por valor: Neste método de passagem de parâmetros, os valores dos parâmetros reais são copiados para os parâmetros formais da função e os dois tipos de parâmetros são armazenados em diferentes locais de memória. Portanto, quaisquer alterações feitas dentro das funções não são refletidas nos parâmetros reais do chamador.

    Exemplo:

    package main
    
    import "fmt"
    
    func swap(a, b int) int {
        var o int
        o = a
        a = b
        b = o
        return o
    }
    
    func main() {
        var p int = 10
        var q int = 20
        
        fmt.Printf("p = %d and q = %d", p, q)
        swap(p, q) // chamada por valor
        fmt.Printf("\np = %d and q = %d",p, q)
    }
    
    // Saída:
    // p = 10 and q = 20
    // p = 10 and q = 20
  • Chamada por referência: Ambos os parâmetros reais e formais referem-se aos mesmos locais, de modo que quaisquer alterações feitas dentro da função são realmente refletidas nos parâmetros reais do chamador. Isto é realizado utilizando ponteiros, que passa o endereço de um tipo para a função. A pilha de funções tem uma referência ao objeto original. Portanto, quaisquer modificações no objeto passado modificarão o objeto original.

    Exemplo:

    package main
    
    import "fmt"
    
    func swap(a, b *int) int {
        var o int
        o = *a
        *a = *b
        *b = o
        return o
    }
    
    func main() {
        var p int = 10
        var q int = 20
    
        fmt.Printf("p = %d and q = %d", p, q)
        swap(&p, &q) // chamada por referência
        fmt.Printf("\np = %d and q = %d",p, q)
    }
    
    // Saída:
    // p = 10 and q = 20
    // p = 20 and q = 10

Função variádica

É a função que é chamada com o número variável de argumentos. Um usuário tem permissão para passar zero ou mais argumentos na função variádica. Fmt.Printf é um exemplo de função variádica, ele exigiu um argumento fixo no início mas depois ele pode aceitar qualquer número de argumentos.

Na declaração da função variádica, o tipo do último parâmetro é precedido por uma reticência, ou seja, (...). Ele indica que a função pode ser chamada em qualquer número de parâmetros desse tipo.

Sintaxe:

function nome_funcao(param1, param2 ...tipo) tipo_retorno {
    // corpo da função.....
}

Note

  • O parâmetro de função variádica deve ser sempre o último e pode haver somente um parâmetro de função variádica.
  • ...tipo se comporta como um slice. Por exemplo, suponha que temos uma assinatura de função, ou seja, add(b... int) int, agora o parâmetro é do tipo []int.
  • Você pode passar um slice existente em uma função variádica.
  • Quando você não passa nenhum argumento na função variádica, então o slice dentro da função será vazio.
  • As funções variádicas são geralmente usadas para funções que executam a formatação de cadeia de caracteres.
  • Você pode passar várias slice na função variádica.
  • Você não pode usar parâmetro variádico como um valor de retorno, mas você pode retorná-lo como um slice.

Exemplo com somente parâmetros de função variádica:

package main

import "fmt"

func main() {
    variadicExample("red", "blue", "green", "yellow")
}

func variadicExample(s ...string) {
    fmt.Println(s[0])
    fmt.Println(s[3])
}

// Saída:
// red
// yellow

Exemplo com parâmetro de função normal com parâmetro de função variádica:

package main

import "fmt"

func main() {
    fmt.Println(calculation("Rectangle", 20, 30))
    fmt.Println(calculation("Square", 20))
}

func calculation(str string, y ...int) int {

    area := 1

    for _, val := range y {
        if str == "Rectangle" {
            area *= val
        } else if str == "Square" {
            area = val * val
        }
    }
    return area
}

// Saída
// 600
// 400

Exemplo com diferentes tipos de argumentos em função variádica:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    variadicExample(1, "red", true, 10.5, []string{"foo", "bar", "baz"}, map[string]int{"apple": 23, "tomato": 13})
}

func variadicExample(i ...interface{}) {
    for _, v := range i {
        fmt.Println(v, "--", reflect.ValueOf(v).Kind())
    }
}

// Saída:
// 1 -- int
// red -- string
// true -- bool
// 10.5 -- float64
// [foo bar baz] -- slice
// map[apple:23 tomato:13] -- map

Função anônima

Uma função anônima é uma função que foi declarada sem qualquer identificador nomeado para se referir a ela. Funções anônimas podem aceitar entradas e retornar saídas, assim como as funções padrão fazem.

Exemplo atribuindo função à variável:

package main

import "fmt"

var (
    area = func(l int, b int) int {
        return l * b
    }
)

func main() {
    fmt.Println(area(20, 30))
}

// Saída: 600

Exemplo passando argumentos:

package main

import "fmt"

func main() {
    func(l int, b int) {
        fmt.Println(l * b)
    }(20, 30)
}

// Saída: 600

Exemplo passando argumentos e retornando valor:

package main

import "fmt"

func main() {
    fmt.Printf(
        "100 (°F) = %.2f (°C)\n",
        func(f float64) float64 {
            return (f - 32.0) * (5.0 / 9.0)
        }(100),
    )
}

// Saída: 100 (°F) = 37.78 (°C)

Função de ordem superior

Uma função de Ordem Superior é uma função que recebe uma função como um argumento ou retorna uma função como saída.

Exemplo passando uma função como argumento:

package main

import "fmt"

func sum(x, y int) int {
    return x + y
}
func partialSum(x int) func(int) int {
    return func(y int) int {
        return sum(x, y)
    }
}
func main() {
    partial := partialSum(3)
    fmt.Println(partial(7))
}

// Saída: 10

Exemplo retornando funções de outras funções:

package main

import "fmt"

func squareSum(x int) func(int) func(int) int {
    return func(y int) func(int) int {
        return func(z int) int {
            return x*x + y*y + z*z
        }
    }
}
func main() {
    // 5*5 + 6*6 + 7*7
    fmt.Println(squareSum(5)(6)(7))
}

// Saída: 110

Tipos de função definidos pelo usuário

Golang também suporta a definição de nossos próprios tipos de função.

package main

import "fmt"

type First func(int) int
type Second func(int) First

func squareSum(x int) Second {
    return func(y int) First {
        return func(z int) int {
            return x*x + y*y + z*z
        }
    }
}

func main() {
    // 5*5 + 6*6 + 7*7
    fmt.Println(squareSum(5)(6)(7))
}

// Saída: 110

Identificador em Branco

O _ (sublinhado) em Golang é conhecido como o Identificador em Branco. Identificadores são o nome definido pelo usuário dos componentes do programa usados para a finalidade de identificação. O Golang tem um recurso especial para definir e usar a variável não utilizada usando o Identificador em Branco. Variáveis não utilizadas são aquelas variáveis que são definidas pelo usuário ao longo do programa mas que nunca são usadas.

O uso real do Identificador em Branco vem quando uma função retorna vários valores, mas precisamos apenas de alguns valores e queremos descartar alguns valores. Basicamente, ele diz ao compilador que essa variável não é necessária e pode ignorá-la sem qualquer erro. Veja o exemplo abaixo:

package main
 
import "fmt"
 
func main() {
    mul, _ := mul_div(105, 7) // obtendo valor da multiplicação e ignorando o da divisão
    fmt.Println("105 x 7 = ", mul)
}

func mul_div(n1 int, n2 int) (int, int) {
     return n1 * n2, n1 / n2
}

Chamas de funções diferidas

Go tem uma instrução especial chamada defer que programa uma chamada de função para ser executada após a conclusão da função. Considere o seguinte exemplo:

package main

import "fmt"

func first() {
    fmt.Println("First")
}
func second() {
    fmt.Println("Second")
}
func main() {
    defer second()
    first()
}

// Saída:
// First
// Second

Uma instrução de diferimento (adiamento) é frequentemente usada com operações emparelhadas, como abrir e fechar, conectar e desconectar ou bloquear e desbloquear para garantir que os recursos sejam liberados em todos os casos, não importa o quão complexo seja o fluxo de controle. O lugar certo para uma instrução de adiamento que libera um recurso é imediatamente após o recurso ter sido adquirido com êxito.

Abaixo está o exemplo para abrir um arquivo e executar a ação de leitura/gravação sem usar o defer:

func ReadWrite() bool {
    file.Open("file")

    if failureX {
        file.Close()
        return false
    }
    if failureY {
        file.Close()
        return false
    }
    file.Close()
    return true
}

Mesmo exemplo mas agora usando defer:

func ReadWrite() bool {
    file.Open("file")
    defer file.Close()

    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}

Note

  • Pode haver mais de uma função diferida no mesmo escopo.
  • As funções diferidas são executadas em ordem LIFO(Last-In, First-Out), ou seja, em forma de pilha.
  • Nas instruções defer, os argumentos são avaliados quando a instrução defer é executada, não quando é chamada.
  • As Funções diferidas são executadas mesmo se ocorrer um pânico (em inglês, panic) de tempo de execução.

Referências