diegoRodicio

Está documentación está a túa disposición sin ningún custo económico. Sen embargo, para a súa elaboración dedico moito tempo e recursos, polo que agradecería unha colaboración co que consideres oportuno. Gracias.

Unha función é un bloque de código que se pode chamar en diferentes partes da nosa aplicación.

Ao crear unha función asignámoslle un nome e dentro delas engadimos o noso código.

Esta agrupación de código ofrécenos varias vantaxes:

  • Podemos dividir e estruturar mellor o código da nosa aplicación
  • Facilitan a reutilización de código
  • Permítenos chamar á función desde diferentes puntos do noso código.

As nosas primeiras funcións #

Para crear unha función debemos usar a keyword func e a continuación debemos engadir o nome da función.

No seguinte exemplo creamos a nosa primeira función en Swift:

func aMiñaPrimeiraFunción() {
    // TODO: Do something
}

Neste caso a función chámase aMiñaPrimeiraFunción e dentro do seu body (todo o que engadimos desde que abrimos as chaves { ata que as pechamos }) podemos engadir a lóxica que queiramos (neste caso a función está baleira).

A unha función dáslle un nome que usarás para chamar á función para que esta execute a súa tarefa.

  • Cada función ten un tipo, o cal se conforma polos tipos dos argumentos da función e do valor de devolución da mesma.
  • Este tipo, pódelo usar como calquera outro tipo en Swift, o cal facilita pasar funcións como parámetros a outras funcións e devolver funcións desde outras funcións.
  • As funcións tamén poden definirse dentro doutras funcións para encapsular funcionalidade útil dentro do ámbito dunha función aniñada.
func saludar(persona: String) -> String {
    let saludo = "¡Hola, " + persona + "!"

    return saludo
}

Definición #

Ao definir unha función, podes especificar —de maneira opcional—:

  • Cada función ten un nome, o cal describe a tarefa que a función executa. O nome da función vai precedido pola palabra chave func
  • Ningún, un ou máis valores de entrada (parámetros).
  • Un valor de saída (valor de devolución). Para indicar o tipo de devolución dunha función, utilizamos a frecha de devolución (->)

Para usar unha función:

  • Debes chamar á función co seu nome
  • Pasarlle valores de entrada (coñecidos como argumentos) que coincidan cos tipos dos parámetros da función. Os argumentos dunha función sempre deben proverse no mesmo orde da lista de parámetros da función.

A función do seguinte exemplo chámase saudar(persoa), xa que iso é o que esta fai, toma o nome dunha persoa como entrada e devolve un saúdo para esta persoa. Para facer isto:

  • Definimos un parámetro de entrada de tipo String chamado persoa
  • Definimos un valor de devolución de tipo String chamado saúdo (o cal contén un saúdo para a persoa)

Vemos o exemplo:

func saudar(persoa: String) -> String {
    let saudo =  "Ola "+persoa+", que tal todo?"
    
    return saudo
}

func saudarOutraVez(persoa: String) -> String {
    return  "Ola "+persoa+", que tal todo?"
}

print(saudar(persoa: "Lola Mento"))
print(saudarOutraVez(persoa: "Lola Mento"))
//Imprimen: Ola Lola Mento, que tal todo?

Parámetros de entrada #

Funcións sen parámetros #

As funcións non requiren de parámetros de entrada.

No seguinte exemplo temos unha función sen parámetros de entrada, a cal sempre devolve o mesmo mensaxe String ao ser chamada:

func olaMundo() -> String {
    return  "Ola mundo"
}
print(olaMundo())
//Imprime: Ola Mundo

Funcións con un parámetro #

Exemplo de dúas funcións, cada unha con un único parámetro de entrada:

func saudar(persoa: String) -> String {
    let saudo =  "Ola "+persoa+", que tal todo?"
    
    return saudo
}

func saudarOutraVez(persoa: String) -> String {
    return  "Ola "+persoa+", que tal todo?"
}

print(saudar(persoa: "Lola Mento"))
print(saudarOutraVez(persoa: "Lola Mento"))
//Imprimen: Ola Lola Mento, que tal todo?

Funcións con varios parámetros #

As funcións poden ter múltiples parámetros de entrada, os cales se escriben dentro das parénteses da función, separados por coma.

Esta función toma como entrada o nome dunha persoa e un Bool para indicar se xa se saudou ou non a esa persoa; devolve un saúdo apropiado para a persoa:

func saudar(persoa: String, foiSaudada: Bool) -> String {
    if(!foiSaudada){
        return  "Ola "+persoa+", que tal todo?"
    }
    else {
        return  "Ola de novo "+persoa
    }
}
print(saudar(persoa: "Lola Mento",foiSaudada: false))
//Imprimen: Ola Lola Mento, que tal todo?
print(saudar(persoa: "Lola Mento",foiSaudada: true))
//Imprimen: Ola de novo Lola Mento

Valor de devolución #

Un valor de devolución #

Exemplo de dúas funcións, cada unha devolven un valor (String):

func saudar(persoa: String) -> String {
    let saudo =  "Ola "+persoa+", que tal todo?"
    
    return saudo
}

func saudarOutraVez(persoa: String) -> String {
    return  "Ola "+persoa+", que tal todo?"
}

print(saudar(persoa: "Lola Mento"))
print(saudarOutraVez(persoa: "Lola Mento"))
//Imprimen: Ola Lola Mento, que tal todo?

Sen valores de devolución #

Hai funcións que non requiren definir un valor de devolución.

Aquí temos unha versión da función saudar(persoa:), a cal imprime a súa propia cadea en lugar de devolvela:

func saudo(persoa: String) {
    print("Ola "+persoa)
}
saudo(persoa: "Aitor Tilla")
//Imprime: Ola Aitor Tilla

Tuplas: Múltiples valores de devolución #

É posible usar unha tupla para devolver múltiples valores.

O seguinte exemplo define unha función chamada minMax, a cal atopa os números menor e maior no array de valores Int que lle pasamos como parámetro:

func minMax(numeros: [Int]) -> (min: Int, max: Int) {
    var minActual = numeros[0]
    var maxActual = numeros[0]
    
    for numero in numeros {
        if (numero<minActual) {
            minActual =  numero
        }
        if (numero>maxActual){
            maxActual = numero
        }
    }
    return (minActual,maxActual)
}

//Outra xeito de facer a función anterior
func minMax2(numeros: [Int]) -> (min: Int, max: Int) {
		//Desempaquetado de opcionais con nil coalescing
    var minActual = numeros.min() ?? 0
    var maxActual = numeros.max() ?? 0
    return (minActual,maxActual)
}

//Outra xeito de facer as funcións anteriores
func minMax3(numeros: [Int]) -> (min: Int, max: Int) {
    //Forzar o Desempaquetado de opcionais.
    //OLLO! Se numeros == nil dará un erro o programa
        
    return (numeros.min()!,numeros.max()!)
}
print(minMax(numeros: [1,9,23,4,56,0]))
//Imprime: (min: 0, max: 56)

let limites = minMax(numeros: [1,9,23,4,56,0])
print("O valor mínimo é \(limites.min) e o máximo é \(limites.max)")
//Imprime: O valor mínimo é 0 e o máximo é 56

Imos ver outro exemplo moi sinxelo. A continuación creamos unha función que retorna unha tupla:

func getTupla() -> (String, String) {
    let ies = "IES San Mamede"
    let curso = "2º DAM"
    return (ies, curso)
}

let (ies, curso) = getTupla()

print(ies)
print(curso)

// RESULTADO 👇
// IES San Mamede
// 2º DAM

Ás veces resulta útil poder retornar unha tupla con poucos valores, pero cando a tupla retorna moitos valores quizais é mellor crear unha Struct ou Class , nos que imos entrar en detalle no seguinte tema de orientación a obxectos.

Múltiples valores de devolución con opcionais #

func minMax(numeros: [Int]) -> (min: Int, max: Int)? {
    if numeros.isEmpty {
        return nil
    }
    else {
        var minActual = numeros[0]
        var maxActual = numeros[0]
        
        for numero in numeros {
            if (numero<minActual) {
                minActual =  numero
            }
            if (numero>maxActual){
                maxActual = numero
            }
        }
        return (minActual,maxActual)
    }
}

print(minMax(numeros: [1,9,23,4,56,0]))
//Imprime: (min: 0, max: 56)
print(minMax(numeros: []))
//Imprime: nil

Etiquetas e nomes de parámetro #

Cada parámetro dunha función ten:

  • Unha etiqueta que se usa ao invocar unha función.
    • Utilízase cando chamamos á función.
    • Nunha mesma función, pódense repetir etiquetas
    • Non é obrigatoria utilizala.
  • O nome do parámetro utilízase na implementación da función.
    • Todos os parámetros deben de ter nomes únicos
    • Se non empregamos etiquetas, o nome do parámetro equivale á etiqueta.

No seguinte exemplo, a función saudar recibe 2 parámetros:

  • O nome da persoa a saudar
    • O nome de parámetro é persona. Émpregase no interior da función
    • Non ten etiqueta, polo que a etiqueta por defecto será o nome do parámetro (persona)
  • A localidade da persoa a saudar
    • O nome de parámetro é: lugarOrixe. Émpregase no interior da función.
    • A etiqueta é de. Émpregase ao chamar á función.
func algunhaFuncion(etiqueta nomeParametro: Int) {

}

func saudar(persona: String, de lugarOrixe: String) -> String {
    return "Ola "+persona+". Gracias pola túa visita dende "+lugarOrixe
}
print(saudar(persona: "Aitor Tilla", de: "Cacharrequille"))
//Imprime: Ola Aitor Tilla. Gracias pola túa visita dende Cacharrequille

Omitindo etiquetas #

Se non queres unha etiqueta de argumento para un parámetro, agrega un guión baixo (_) en lugar dunha etiqueta.

Así, na seguinte función, omitimos a etiqueta para o parámetro numeros, de xeito que, ao chamar a función, en lugar de minMax3(numeros:[1,9,23,4,56,0]), ao non ter etiqueta, utilizamos minMax3([1,9,23,4,56,0]):

func minMax(_ numeros: [Int]) -> (min: Int, max: Int) {
    var minActual = numeros[0]
    var maxActual = numeros[0]
    
    for numero in numeros {
        if (numero<minActual) {
            minActual =  numero
        }
        if (numero>maxActual){
            maxActual = numero
        }
    }
    return (minActual,maxActual)
}

print(minMax([1,9,23,4,56,0]))
//Imprime: (min: 0, max: 56)

Parámetros variables #

Podemos enviar varios valores dun parámetro específico insertado tres puntos (...) despois do parámetro:

func mediaAritmetica(_ numeros: Double...) -> Double {
    var total: Double = 0

    for numero in numeros {
        total += numero
    }

    return total / Double(numeros.count)
}

print(mediaAritmetica(1, 2, 3, 4, 5))
// Devuelve 3.0, que es la media aritmética de esos cinco números.
print(mediaAritmetica(3, 8.25, 18.75))
// Devuelve 10.0, que es la media aritmética de esos tres números.

Parámetros por defecto #

Os parámetros de entrada dunha función poden ter valores por defecto:

func createDatabase(name: String, path: String = "/") {
    print(path)
}

Neste caso, creamos unha función que ten dous parámetros de entrada, e o segundo ten un valor por defecto

Isto significa que poderiamos chamar á función da seguinte maneira:

createDatabase(name: "Alumnado_2_DAM")
// Imprime: /

createDatabase(name: "Alumnado_2_DAM", path: "/users/root")
// Imprime: /users/root

Na primeira chamada o método createDatabase omitimos escribir o segundo parámetro xa que dentro do body da función queremos usar «/» (que é o valor por defecto que está asignado a ese parámetro).

Pero na seguinte chamada ao método createDatabase, estamos a especificar o segundo parámetro cunha ruta que non queremos que sexa o valor por defecto «/«, por tanto sobrescribimos o valor por «/users/root«.

in-out: Parámetros de E/S #

Os parámetros das funcións son, por defecto, constantes.

  • Tentar cambiar o valor do parámetro dentro do corpo da función resultará nun erro de tempo de compilación.
  • Isto significa que non podes cambiar o valor dun parámetro por accidente.

Para que unha función modifique o valor dun parámetro e que os cambios persistan despois de finalizada a execución da función, debemos definir devandito parámetro como un parámetro in-out.

  • Para definir un parámetro in-out, agrega a palabra chave inout xusto antes do parámetro.
  • Soamente podes pasar unha variable como o argumento para un parámetro in-out. Non é posible pasar unha constante.
  • Ao pasar unha variable como argumento para un parámetro in-out, agrega o símbolo ampersand (&) xusto antes do nome da variable, para indicar que esta pode ser modificada pola función.
func intercambiarDousEnteiros(_ a: inout Int, _ b: inout Int) {
    let aTemporal = a
    
    a = b
    b = aTemporal
}

var algunEnteiro = 3
var otroEnteiro = 107

intercambiarDousEnteiros(&algunEnteiro, &otroEnteiro)

print("algunEnteiro agora é \(algunEnteiro), e otroEnteiro é agora \(otroEnteiro)")
// Imprime: algunEnteiro agora é 107, e otroEnteiro é agora 3

Funcións anidadas #

É posible definir funcións dentro doutras funcións, o que se coñece como funcións aniñadas.

As funcións aniñadas están ocultas do mundo exterior, pero poden ser chamadas e usadas polas funcións que as conteñen. Unha función que contén unha ou máis funcións aniñadas tamén pode devolver unha das súas funcións aniñadas para permitirlle ser usada noutro ambiente.

func elegirFuncionDeMovimiento2(debeRegresar: Bool) -> (Int) -> Int {
    func avanzar(input: Int) -> Int { return input + 1 }
    func regresar(input: Int) -> Int { return input - 1 }

    return debeRegresar ? regresar : avanzar
}

var valorActual = -4
var moverseHaciaCero = elegirFuncionDeMovimiento2(debeRegresar: valorActual > 0)
// moverseHaciaCero ahora se refiere a la función anidada avanzar()

while valorActual != 0 {
    print("Valor actual: \(valorActual)... ")
    valorActual = moverseHaciaCero(valorActual)
}
//Imprime:
//Valor actual: -4...
//Valor actual: -3...
//Valor actual: -2...
//Valor actual: -1...

Share Your Valuable Opinions