Invocació de funcions

4575

Com recordeu, hem comentat les funcions abans. Què és una funció, però? Com els podem utilitzar? Una funció és una seqüència d'instruccions , podem invocar-la des d'un programa cridant-ne el nom. Les funcions representen subprogrames i realitzen algunes accions, per exemple, imprimir dades a la sortida estàndard, calcular una arrel quadrada, etc.

La imatge següent mostra com funcionen les funcions. Bàsicament, és només una caixa que processa arguments d'entrada ( dades d'entrada ) i produeix un resultat útil o res.

flowchart LR
   f["Funció"] 
   . -- arguments --> f
   f -- resultat o res --> x

Arguments de funcions

Quan volem utilitzar una funció, podem invocar-la (o cridar-la) utilitzant el seu nom seguit de parèntesis. Si una funció pren un o més arguments (dades d'entrada), s'han de passar entre parèntesis.

A l'exemple següent, invoquem la printlnfunció amb un argument d'una sola cadena:

val text = "Hello" println(text)

Aquesta funció tampoc pot prendre cap argument per imprimir una línia nova :

println()

Per tant, en la seva forma general, una funció es pot invocar així:

function1() // invokes function1 without an argument function2(arg1) // invokes function2 while passing an argument function3(arg1, arg2) // invokes function3 while passing two arguments // ... and so on

On functionés el nom d'una funció.

Produir un resultat

Algunes funcions no només prenen arguments sinó que també produeixen (retorn) alguns resultats. També podeu assignar-lo a una variable:

val result = function(arg)

Les funcions que prenen arguments i produeixen un resultat semblen funcions matemàtiques normals.

Per exemple, fem una ullada a una funció matemàtica que retorna el valor absolut d'un nombre:

val number = -10 val nonNegNumber = Math.abs(number) // it takes -10 and returns 10

Un avantatge d'utilitzar funcions és que no cal que implementeu res, només cal que invoqueu una funció i funcionarà.

El nom de la absfunció s'escriu després del símbol de punt. El motiu és que Mathagrupa múltiples funcions, i hauríem d'escriure el nom del grup per invocar una d'elles. No entrarem en detalls ara mateix, només tingueu en compte que veureu alguna cosa així als nostres exemples i problemes de pràctica.

Totes les funcions retornen un resultat, fins i tot la printlnfunció.

val result = println("text") println(result) // kotlin.Unit

El resultat és un valor especial anomenat Unit, que pràcticament significa no result. Quan la vostra funció no retorna res, vol dir que torna Unit, això és tot el que heu d'entendre de moment. Si veniu d'un altre llenguatge com C o Java, podeu pensar-hi com Void.

Activitats

1.- Sam i Frodo van decidir comptar quant pa tenien. Per fer-ho, han creat una funció totalLembasque compta la quantitat de pa que tenen en total.

La vostra tasca és invocar la funció totalLembas; passar breadFromFrodoi breadFromSamcom a arguments.

// This is the totalLembas() function. It just counts the total number of lembas. 
// Do not change this code
fun totalLembas(first: String, second: String) {
    print(first.toInt() + second.toInt())
}

fun main() {
    val breadFromFrodo = readln()
    val breadFromSam = readln()

    // write your code here

}

Declaració de funcions

4580

A Kotlin, les funcions formen la base del vostre codi. Defineixen blocs de codi que podeu executar i reutilitzar al llarg del vostre programa. Declareu funcions a Kotlin utilitzant la fun paraula clau , un nom, una llista de paràmetres (si cal), el tipus de retorn i el cos de la funció.

Les funcions tenen un paper crític perquè organitzen el codi en fragments manejables. Permeten la reutilització del codi, alleugereixen les redundàncies i milloren la llegibilitat. Quan embolcalleu operacions específiques dins de funcions, creeu bases de codi més modulars i que es puguin mantenir.

Vegem un exemple senzill d'una declaració de funció de Kotlin :

fun greet(name: String): String { return "Hello, $name!" }

En aquest cas , greetés una funció que accepta un paràmetre namede tipus Stringi retorna un missatge de salutació com a String. Per utilitzar aquesta funció, només heu de passar un nom:

val message = greet("Alice") println(message) // Output: Hello, Alice!

Kotlin també inclou suport per a arguments amb nom i valors de paràmetres predeterminats, que aporten flexibilitat addicional a les funcions:

fun greet(name: String, greeting: String = "Hello"): String { return "$greeting, $name!" }

val customGreeting = greet(name = "Bob", greeting = "Welcome") println(customGreeting) // Output: Welcome, Bob!

Saber declarar i utilitzar funcions és primordial per treballar amb Kotlin, ja que s'utilitzen habitualment en tot tipus d'aplicacions.

A Kotlin, la sintaxi fonamental per declarar una funció és la següent:

fun functionName(param1: Type1, param2: Type2, ...): ReturnType { // Function body return value }

Aquí teniu un desglossament de la sintaxi:

fun: Aquesta paraula clau declara una funció.

functionName: Aquest és el nom que doneu a la vostra funció. Feu que sigui descriptiu i seguiu la convenció de nomenclatura de camelCase.

param1, param2, ..., Type1, Type2, ...: representen els paràmetres de la funció. Cada paràmetre consta d'un nom seguit de dos punts i el seu tipus. Les funcions poden ser sense paràmetres.

ReturnType: Això etiqueta el tipus de valor que retornarà la funció. Si la funció no retorna cap valor, el tipus de retorn és Unit, que podeu ometre.

Aquí teniu un exemple de funció senzilla que pren dos nombres enters i retorna la seva suma:

fun addNumbers(a: Int, b: Int): Int { return a + b }

Kotlin proporciona una sintaxi més ordenada per a funcions amb una única expressió utilitzant el =signe:

fun multiplyNumbers(a: Int, b: Int): Int = a * b

En aquest cas, podeu ometre el tipus de retorn si el compilador pot discernir-lo:

fun multiplyNumbers(a: Int, b: Int) = a * b

A Kotlin, en definir una funció, podeu especificar els paràmetres que acceptarà la funció. Els paràmetres es descriuen entre parèntesis després del nom de la funció, i cada paràmetre inclou un nom, dos punts i el seu tipus. Aquí teniu un exemple bàsic:

fun greet(name: String) { println("Hello, $name!") }

Podeu assignar valors per defecte per als paràmetres de funció. Aquesta capacitat us permet invocar la funció sense haver de passar tots els arguments de manera explícita, recorrent als valors per defecte. Els valors per defecte s'anoten utilitzant l' =operador després del tipus:

fun greet(name: String, greeting: String = "Hello") { println("$greeting, $name!") }

Amb la funció anterior, podeu trucar greet("Alice")i imprimirà "Hola, Alice!" perquè greetings'utilitza el valor predeterminat de .

Kotlin també admet arguments amb nom, cosa que us permet anotar els noms dels paràmetres quan invoqueu la funció. Aquesta característica és especialment útil quan una funció té nombrosos paràmetres amb valors predeterminats i voleu proporcionar un valor no predeterminat per a un paràmetre que no sigui l'últim de la llista:

greet(name = "Bob", greeting = "Hi")

Els arguments amb nom amplien la llegibilitat del codi i permeten cridar funcions amb paràmetres en un ordre diferent de com es van definir.

Tipus de retorn i unitat a les funcions de Kotlin

A Kotlin, les funcions poden retornar diferents tipus de valors, especificats seguint el nom i els paràmetres de la funció, precedits de dos punts. Per exemple, una funció que retorna un Intes declararia així:

fun sum(a: Int, b: Int): Int { return a + b }

El tipus de retorn es pot veure clarament a la signatura de la funció. Tanmateix, si la funció no retorna cap valor valuós, Kotlin proporciona el Unittipus, comparable a voiden llenguatges com Java o C++. No és necessari especificar Unitcom a tipus de retorn perquè és el tipus de retorn predeterminat si no es declara cap:

fun printSum(a: Int, b: Int): Unit { println("Sum is ${a + b}") }

// is equivalent to

fun printSum(a: Int, b: Int) { println("Sum is ${a + b}") }

Quan una funció torna Unit, implica que la funció s'invoca pels seus efectes secundaris (com la impressió a la consola), no pel resultat que retorna.

Activitats

1.- Escriu una funció anomenada isRightEquation()que prengui tres nombres i retorni truesi el producte dels dos primers nombres és igual al tercer nombre. En cas contrari, hauria de tornar false.

Exemples: 2,3,6 -> true; 2,3,7 -> false

// write your code here

/* Do not change code below */
fun main() {
    val a = readLine()!!.toInt()
    val b = readLine()!!.toInt()
    val c = readLine()!!.toInt()
    println(isRightEquation(a, b, c))
}

La funció main()

10491

Suposo que us heu fet la pregunta de per què hem d'escriure exactament fun main() {}a cada programa. Ara anem a arribar al fons d'això!

La funció main().

Per tant, mireu més de prop la main()funció. De fet, és una cosa molt habitual: pots fer exactament el que fas amb qualsevol altra funció. L'única diferència és que és el punt d'entrada del programa. Això vol dir que l'execució del programa comença cridant aquesta funció.

Vegem més de prop en què main()consisteix:

fun main() {}

funés una paraula clau que mostra que main()és una funció. Només una funció normal;

mainés el nom de la funció. És important saber que no el podem canviar: si el canviem, per exemple, a Main(), el programa es compilarà però no s'iniciarà;

i finalment, el cos de la funció, com bé sabeu, es col·locarà entre tirants.

De fet, encara pot haver-hi paràmetres d'entrada — args— a la main()sintaxi; és una part no vinculant de la declaració de la main(), i en parlarem més endavant.

Per tant, qualsevol cosa que pugueu fer amb una funció habitual, excepte canviar el nom, es pot fer amb main().

La seva característica principal és que la seva existència és obligatòria: sense ell, el programa no s'iniciarà. Però main()també es pot cridar a propòsit. Per exemple, es pot anomenar per si mateix:

var decrease = 3

fun main() { if (decrease == 0) return decrease = decrease - 1 println(decrease) main() }

En aquest programa, cada trucada a main()disminueix el valor de la variable global decreaseen 1 i imprimeix el valor actual, fins que sigui igual a 0. La paraula "global" significa que aquesta variable és accessible des de qualsevol lloc del programa, entre altres, en la main()funció.

La sortida d'aquest codi és així:

2 1 0

Arguments de la funció principal

De fet, la main()funció pot tenir paràmetres d'entrada. S'han de cridar argsi emmagatzemar en una matriu de cadenes. I la sintaxi de main()will es veurà així:

fun main(args: Array<String>) {}

El treball amb argses porta a terme de la mateixa manera que amb altres matrius: per exemple, args.sizeretornarà el nombre d'arguments i args[1]retornarà el segon argument al programa.

Sí, però per a què serveix?

En paraules simples, els arguments de la main()funció són els arguments del programa. Probablement heu aprofitat l'oportunitat de configurar-lo moltes vegades a la vostra vida, per exemple, quan heu obert un fitxer amb "Obre amb...": en aquest cas, la ubicació del fitxer es passa mitjançant els arguments del programa.

Per tant, utilitzant els main()arguments, transmetem algunes dades externes addicionals al propi programa.

Treballant amb la línia d'ordres

De fet, podem passar arguments al programa utilitzant les eines de l'IDE o la línia d'ordres. Ja sabeu com es pot fer amb l'IDE. L'altra manera és una mica més complicada.

Considereu-ho amb més detall: és un enfocament únic i, de totes maneres, es necessitaran habilitats de línia d'ordres moltes vegades al camí del vostre programador. Per exemple, en casos senzills, pot obviar la necessitat de crear una interfície gràfica per interactuar amb l'usuari. No tingueu por si aquest enfocament sembla massa complicat ara: aquest és només un exemple de com establir els arguments del programa exactament amb la línia d'ordres.

Per enviar arguments de línia d'ordres a la vostra aplicació, necessiteu un programa precompilat.

Per tant, considereu com podeu passar arguments a través de la consola: en primer lloc, necessiteu un programa compilat. Quan en teniu un, truqueu a la línia d'ordres. Després d'això, executeu l'aplicació amb l'ordre següent:

$ java -jar filename.jar args

Tanmateix, en aquesta ordre, després d'especificar un fitxer filenameamb l'extensió .jar, podeu passar exactament els arguments del programa argsseparats per un espai. Ara mirem com funciona tot això en un exemple molt senzill.

Un exemple pràctic

Vegem el següent codi:

fun main(args: Array<String>) {
    println(args[0])
    println(args[1])
}

Aquest programa genera les dues primeres cadenes que s'han especificat com a arguments del programa. Deixeu que aquest programa estigui al fitxer anomenat print_args.kt. I passem, per exemple, els següents arguments del programa (o arguments de la main()funció): "Hola", "Kotlin!". Fes-ho amb la línia d'ordres:

$ java -jar print_args.jar Hello, Kotlin!

Aleshores el resultat serà el següent:

Per tant, el nostre codi s'ha implementat de la següent manera:

fun main(args: Array) { println(args[0]) // Hello, println(args[1]) // Kotlin! }

Si en canvi passem "Amor", "Kotlin!", s'imprimirà el següent:

Per tant, en no canviar res al codi, afectem el resultat del programa establint arguments de main().

Amb o sense arguments?

Com hem esmentat anteriorment, la main()funció pot existir amb o sense arguments. A tall d'il·lustració, executem el mateix codi que no utilitza els arguments del programa de dues maneres:

fun main(args: Array) { val firstName = "Luke" val lastName = "Skywalker" println(firstName + " " + lastName) // Luke Skywalker }

fun main() { val firstName = "Luke" val lastName = "Skywalker" println(firstName + " " + lastName) // Luke Skywalker }

Així que tot funciona!

A més, no hi haurà cap error quan el vostre fitxer contingui les dues versions de main()- amb i sense arguments. El programa només començarà executant main(args: Array ) {}:

fun main(args: Array) { println(args[0]) // Love println(args[1]) // Kotlin! }

fun main() { println("Hello, World!") } // will not be called

Tanmateix, heu de recordar que no hi pot haver diverses main()declaracions en un fitxer amb arguments o main()declaracions múltiples sense aquests alhora! Les dues variants de la main()declaració només poden estar presents en una instància, igual que en qualsevol altra funció.

Què passa amb l'altre tipus, l'altre nombre i un altre nom d'arguments? Per descomptat, podeu tenir una main()funció amb paràmetres d'entrada completament diferents en un fitxer, per exemple, pot ser main(arg: Int)o main(a: Double, b: String), però llavors ja no serà un punt d'entrada. Serà només una funció comuna. Perquè el programa s'iniciï, el fitxer del programa ha de contenir una funció amb la signatura main()o main(args: Array).

En resum, podeu utilitzar argsquan necessiteu treballar amb arguments de programa. Però si el vostre programa no requereix arguments de línia d'ordres, els arguments de línia d'ordres es poden ometre. Abans de Kotlin 1.3, havies d'escriure main(args: Array), però ara no cal

Activitats

1.- El codi s'inicia amb 1 argument de programa.

Escriu el codi a la main()funció que mostra la cadena passat com a argument al programa.

fun main(args: Array<String>) {
    TODO()
}

Arguments per defecte

4637

En qualsevol llenguatge de programació, les funcions són instruments realment potents. De vegades no cal que utilitzeu tots els arguments d'una funció, ja que alguns d'ells es poden emmagatzemar com a valors preseleccionats. En aquest tema, aprendràs a fer-ho.

Funcions amb arguments per defecte

Kotlin pot assignar valors per defecte als paràmetres de funció a la declaració de funció . Per invocar la funció, podeu ometre els arguments amb valors predeterminats o invocar-la de la manera habitual.

Aquí hi ha una funció anomenada printLineamb dos paràmetres. El primer paràmetre defineix una línia, el segon paràmetre és una cadena que acaba aquesta línia. Tots dos paràmetres tenen valors per defecte: una línia buida ( "") i una línia nova ( "\n").

fun printLine(line: String = "", end: String = "\n") = print("$line$end")

Mireu aquest exemple: assignem valors als paràmetres mitjançant l' =operador després dels tipus.

Fes una ullada a un fragment de codi complet. Té les funcions següents: printLinei main.

fun printLine(line: String = "", end: String = "\n") = print("$line$end")

fun main() { printLine("Hello, Kotlin", "!!!") // prints "Hello, Kotlin!!!" printLine("Kotlin") // prints "Kotlin" with an ending newline printLine() // prints an empty line like println() }

Durant la primera trucada, es passen dos arguments a la funció ( "Hello, Kotlin"i "!!!"). Durant la segona crida, només es passa un argument ( "Kotlin"), el valor del segon paràmetre és per defecte ( "\n"). Durant la tercera trucada, no passem cap argument, però encara funciona perquè tots dos paràmetres tenen valors per defecte.

Els resultats del programa:

Hello, Kotlin!!!Kotlin

No podem passar el segon argument sense el primer. Kotlin no entén que volem assignar un valor només al segon paràmetre.

Barreja d'arguments per defecte i regulars

També podeu barrejar paràmetres predeterminats i regulars durant la declaració. Per exemple, la funció següent troba el màxim de dos arguments enters. Té un paràmetre especial que determina si cal comparar nombres pels seus valors absoluts. El valor per defecte d'aquest paràmetre és false.

fun findMax(n1: Int, n2: Int, absolute: Boolean = false): Int { val v1: Int val v2: Int

if (absolute) { v1 = Math.abs(n1) v2 = Math.abs(n2) } else { v1 = n1 v2 = n2 }

return if (v1 > v2) n1 else n2 }

fun main() { println(findMax(11, 15)) // 15 println(findMax(11, 15, true)) // 15 println(findMax(-4, -9)) // -4 println(findMax(-4, -9, true)) // -9 }

Al cos de la findMaxfunció, declarem dues variables temporals. Emmagatzemen valors absoluts o els mateixos valors dels arguments, depenent del valor de l'absolut. L'última línia compara variables temporals i retorna el valor de l'argument corresponent.

Anomenem la findMaxfunció en el cos de mainquatre temps. La primera trucada retorna el valor màxim ( 15), la segona trucada retorna el valor màxim de nombres positius ( 15), la tercera trucada retorna el valor màxim de dos nombres negatius ( -4) i l'última trucada retorna el valor màxim amb el valor absolut de dos nombres negatius.

Els arguments per defecte permeten als programadors crear un comportament opcional o de casos especials per a les seves funcions.

Idioma Els arguments de funció per defecte formen part dels modismes de Kotlin . És una bona pràctica afegir arguments per defecte, són útils quan escriu funcions complexes.

fun foo(a: Int = 0, b: String = "") {

}

Activitats

1.- Creeu una funció anomenada sum5que pugui sumar de 2 a 5 nombres.

Exemple: 8, 11 -> 19

fun sum5(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int): Int {

}

Arguments amb nom

Quan invoquem una funció que té alguns paràmetres, podem passar arguments pels noms d'aquests paràmetres. Aquest enfocament pot millorar la llegibilitat del vostre codi, especialment si una funció té molts paràmetres. A més, és una manera convenient de canviar l'ordre dels arguments passats en una trucada de funció.

Millora de la llegibilitat del codi Imagineu-vos un caixer que ven entrades de cinema i el preu de l'entrada segueix sent el mateix al llarg d'un dia. Cal calcular quants diners tindrà el nostre caixer al final de la jornada laboral. Ho podem fer amb una funció que té tres paràmetres:

fun calcEndDayAmount(startAmount: Int, ticketPrice: Int, soldTickets: Int) = startAmount + ticketPrice * soldTickets

startAmountés una suma inicial a la caixa.

ticketPriceés el preu d'un bitllet.

soldTicketsés el nombre d'entrades venudes aquest dia.

És una funció normal, així que podem invocar-la així:

val amount = calcEndDayAmount(1000, 10, 500) // 6000

Això funcionaria bé, tot i que hi ha un problema: arguments poc clars. Per descomptat, podem declarar variables estàndard i transmetre-les, però de vegades cal treballar amb literals, no amb variables. Els arguments amb nom poden fer que el nostre codi sigui més llegible. Per solucionar aquest problema, podeu anomenar cada argument d'aquesta funció:

val amount = calcEndDayAmount( startAmount = 1000, ticketPrice = 10, soldTickets = 500 ) // 6000

Ara, el codi és fàcil d'entendre!

Reordenació dels arguments

Podeu canviar l'ordre dels arguments en una crida de funció amb l'ajuda d'arguments amb nom. Tot el que heu de fer és especificar els noms en l'ordre que vulgueu:

val amount = calcEndDayAmount( ticketPrice = 10, soldTickets = 500, startAmount = 1000 ) // 6000

Arguments denominats i posicionals

També podeu cridar una funció amb arguments amb nom i regulars (posicionals), sempre que els arguments amb nom es col·loquin després dels posicionals:

calcEndDayAmount(1000, ticketPrice = 10, soldTickets = 500) // 6000

Kotlin 1.4 o posterior us permet utilitzar arguments posicionals després dels arguments amb nom, però heu de mantenir-ne l'ordre. Per exemple:

calcEndDayAmount(ticketPrice = 10, 500, 1000) // Incorrect invocation! calcEndDayAmount(startAmount = 1000, 10, 500) // OK

calcEndDayAmount(soldTickets = 500, ticketPrice = 10, startAmount = 500) // OK calcEndDayAmount(soldTickets = 500, ticketPrice = 10, 500) // Incorrect invocation!

Arguments per defecte i amb nom

També podeu utilitzar arguments amb nom i per defecte junts. Com probablement sabreu, els arguments predeterminats de vegades són confusos, ja que és possible que Kotlin no entengui quins paràmetres cal assignar.

Modifiquem la funció anterior i fem que el primer paràmetre sigui opcional:

fun calcEndDayAmount(startAmount: Int = 0, ticketPrice: Int, soldTickets: Int) = startAmount + ticketPrice * soldTickets

Suposem que ens agradaria invocar aquesta funció amb només dos darrers paràmetres. Però no funcionarà:

val amount = calcEndDayAmount(10, 500) // Won't work — // no value for soldTickets

Aquí 10s'assigna al primer argument opcional startAmount, no al segon paràmetre ticketPrice.

Per invocar aquesta funció, utilitzeu arguments amb nom:

val amount = calcEndDayAmount(ticketPrice = 10, soldTickets = 500) // 5000

Ara funciona!

Arguments amb nom i valors per defecte

Els valors per defecte dels paràmetres de funció poden ser constants o no. També poden ser un altre argument amb nom o una funció.

Per exemple:

fun sum2(a: Int, b: Int = a) = a + b

sum2(1) // 1 + 1 sum2(2, 3) // 2 + 3

El codi següent no funcionarà, ja que el bparàmetre no està inicialitzat:

fun sum2(a: Int = b, b: Int) = a + b

Activitats

1.- Escriu una funció anomenada urlque creï l'URL d'un recurs. La funció té dos paràmetres hosti porti retorna l'URL en el format següent: https://HOST:PORT. Tots dos hostparàmetres portsón opcionals i tenen els valors per defecte següents: localhost i 443 respectivament.

fun url(host: String, port: Int): String {
    // TODO
}

Descomposició funcional

12668

La descomposició funcional és un procés en el desenvolupament de programari on un sistema complex es divideix en components més simples i més fàcils de gestionar, també coneguts com a funcions o mòduls. Aquest mètode és essencial per entendre, mantenir i millorar el programari separant les funcionalitats; això fomenta la reutilització i la prova del codi.

Per exemple, imagineu una funció de Kotlin que s'ocupa d'una llista d'elements:

fun processItems(items: List) { items.forEach { processItem(it) } }

fun processItem(item: Item) { // Logic to process a single item }

En aquest cas, processItemssimplifica la tasca de maneig d'una col·lecció dividint-la en el processament d'elements individuals, que processItems'encarrega. Aquesta divisió fa que sigui més fàcil entendre i provar la funció de cada part per separat.

Principis bàsics de la descomposició funcional a Kotlin

Aquest mètode està en línia amb el suport de Kotlin per a l' estil de programació funcional . Aquests són alguns conceptes fonamentals:

Funcions pures: el resultat d'una funció pura només depèn dels seus valors d'entrada i no té efectes secundaris notables. Aquesta predictibilitat fa que sigui més senzill entendre què farà la funció.

fun add(a: Int, b: Int): Int { return a + b // Pure function }

Immutabilitat: un cop creades, les dades immutables no es poden alterar. Això evita problemes amb estats compartits i fa que els entorns concurrents siguin menys arriscats.

val list = listOf(1, 2, 3) // Immutable list

Funcions d'ordre superior : les funcions de Kotlin poden prendre altres funcions com a paràmetres o funcions de retorn, fent que el codi sigui més modular i reutilitzable.

fun applyOperation(a: Int, b: Int, operation: (Int, Int) -> Int): Int { return operation(a, b) // Higher-order function usage }

val sum = applyOperation(2, 3, ::add) // Passes ::add as a parameter

Seguir aquests principis permet als desenvolupadors de Kotlin crear codi que sigui més fàcil de provar, mantenir i ampliar.

Patrons de disseny funcional a Kotlin

Aquests patrons ajuden a simplificar situacions complexes, un procés conegut com a descomposició funcional, que millora l'organització i el manteniment del codi.

Mónades

Les mónades són estructures que embolcallen la lògica de càlcul. A Kotlin, el Resulttipus és una mónada que pot contenir un valor o una excepció. Les mónades us permeten enllaçar operacions alhora que gestioneu els errors sense problemes.

val result: Result = Result.runCatching { someRiskyOperation() } result.map

Functors

Els funcionals són estructures que es poden mapejar, com a ListKotlin. Apliquen una funció als valors embolcallats sense canviar l'estructura real.

val numbers = listOf(1, 2, 3) val squared = numbers.map { it * it } // Functor usage

Tail Recursion

Tail Recursion és un patró on una funció s'anomena a si mateixa al final de la seva operació, permetent al compilador optimitzar la pila de trucades . Kotlin admet la recursió de la cua amb el tailrecmodificador.

tailrec fun factorial(n: Int, acc: Int = 1): Int { return if (n == 1) acc else factorial(n - 1, n * acc) }

Aquests patrons milloren la descomposició funcional proporcionant maneres estructurades de gestionar dades i càlculs, fent que el codi sigui més previsible i més senzill d'entendre. El suport de Kotlin per a aquests patrons permet als desenvolupadors escriure codi concís i senzill, abraçant el millor de la programació funcional.

Activitats

1.- Una equació de segon grau és una equació algebraica de segon grau. Són fàcils de resoldre si coneixeu la fórmula quadràtica .

Aquí hi ha una funció senzilla per calcular les arrels reals d'una equació de segon grau:

fun findRoots(a: Double, b: Double, c: Double) {
    // the equation is ax^2 + bx + c = 0
    val discriminant = b * b - 4 * a * c
    when {
        discriminant < 0.0 -> {
            println("No real roots!")
        }
        discriminant == 0.0 -> {
            val x = -b / (2 * a)
            println("x = $x")
        }
        else -> {
            val x1 = (-b + discriminant.pow(0.5)) / (2 * a)
            val x2 = (-b - discriminant.pow(0.5)) / (2 * a)
            println("x1 = $x1")
            println("x2 = $x2")
        }
    }
}

Si descomposem aquest codi, tindrem les funcions següents:

fun calculateDiscriminant(a: Double, b: Double, c: Double): Double {
    return b * b - 4 * a * c
}

fun calculateRoots(a: Double, b: Double, c: Double, discriminant: Double) {
    val x1 = (-b + discriminant.pow(0.5)) / (2 * a)
    val x2 = (-b - discriminant.pow(0.5)) / (2 * a)
    if (x1 == x2) {
        println("x = $x1")
    } else {
        println("x1 = $x1")
        println("x2 = $x2")
    }
}

Com hauria de ser la funció després de la descomposició?

fn main() {
    val a = readln().toDouble()
    val b = readln().toDouble()
    val c = readln().toDouble()

    // TODO
}

Call Stack