Kotlin From Scratch Paket och grundläggande funktioner

Kotlin är ett modernt programmeringsspråk som kompilerar till Java bytecode. Det är gratis och öppen källkod, och lovar att göra kodning för Android ännu roligare. 

I den föregående artikeln lärde du dig om intervall och samlingar i Kotlin. I den här handledningen fortsätter vi att lära sig språket genom att titta på hur man organiserar kod med hjälp av paket och sedan gå vidare till en introduktion till funktioner i Kotlin.

1. Paket

Om du är bekant med Java vet du att Java använder paket för att gruppera relaterade klasser; till exempel, java.util paketet har ett antal användbara verktygsklasser. Paketet deklareras med paket sökord och någon Kotlin-fil med a paket deklarationen i början kan innehålla deklarationer av klasser, funktioner eller gränssnitt.

Deklaration

Titta på koden nedan har vi förklarat ett paket com.chikekotlin.projectx använda paket nyckelord. Vi förklarade också en klass Min klass (vi diskuterar klasser i Kotlin i framtida inlägg) i detta paket.

paket com.chikekotlin.projectx klass MyClass

Nu är det fullt kvalificerade namnet för klassen Min klass är com.chikekotlin.projectx.MyClass.

paket com.chikekotlin.projectx fun saySomething (): String returnera "Hur långt?" 

I koden ovan skapade vi en toppnivåfunktion (vi kommer snart till det). Så på samma sätt som Min klass, det fullt kvalificerade namnet på funktionen Säg något() är com.chikekotlin.projectx.saySomething.

import

I Kotlin använder vi importera deklaration så att kompilatorn kan hitta de klasser, funktioner, gränssnitt eller objekt som ska importeras. I Java kan vi däremot inte direkt importera klasser eller gränssnitt för funktioner eller metoder. 

Vi använder importera för att komma åt en funktion, gränssnitt, klass eller objekt utanför paketet där det deklarerades. 

importera com.chikekotlin.projectx.sayNågot roligt huvud (args: Array) saySomething () // kommer att skriva ut "Hur långt?" 

I kodfältet ovan importerade vi funktionen Säg något() från ett annat paket, och då utförde vi den funktionen.

Kotlin stöder också jokerteckenimport med * operatör. Detta kommer att importera alla klasser, gränssnitt och funktioner som deklareras i paketet på en gång. Det här rekommenderas inte, men det är oftast bättre att göra din import tydlig.

importera com.chikekotlin.projectx. *

Import Aliasing

När du har bibliotek som har motstridiga klass- eller funktionsnamn (t.ex. deklarerar var och en en funktion med samma namn) kan du använda som sökord för att ge den importerade enheten ett tillfälligt namn.

importera com.chikekotlin.projectx.sayNågot import com.chikekotlin.projecty.sayNågot som projectYSayNågot kul huvud (args: Array) projectYSaySomething ()

Observera att det tillfälliga namnet endast används i filen där den tilldelades.

2. Funktioner

En funktion grupperar en serie koddeklarationer som utför en uppgift. Detaljerna för implementeringen av funktionen är dolda från den som ringer.

I Kotlin definieras funktioner med hjälp av roligt sökord, som visas i följande exempel:

roligt hej (namn: String): String return "Hej $ namn" val meddelande = hej ("Chike") utskrift (meddelande) // kommer att skriva ut "Hello Chike"

I koden ovan definierade vi en enkel funktion Hej() med en enda parameter namn av typ Sträng. Den här funktionen returnerar a Sträng typ. Parameterdefinitionsformatet för funktioner är namn: typ, t.ex. ålder: Int, pris: dubbel, student: StudentClass.

roligt hej (namn: String): Enhet print ("Hej $ namn") hej ("Chike") // kommer att skriva ut "Hello Chike"

Funktionen ovan liknar den föregående men märker att den här har en returtyp av Enhet. Eftersom den här funktionen inte ger något betydande värde för oss, skrivs det bara ut ett meddelande-dess returtyp är Enhet som standard. Enhet är ett Kotlin-objekt (vi diskuterar Kotlin-objekt i senare inlägg) som liknar Ogiltig typer i Java och C.

offentligt objekt Enhet överrätta rolig toString () = "kotlin.Unit"

Observera att om du inte uttryckligen förklarar returtypen att vara Enhet, typen är avledd av kompilatorn.

rolig hej (namn: String) // kommer fortfarande att kompilera utskrift ("Hej $ namn")

Enradiga funktioner

Enradiga eller enradiga funktioner är funktioner som bara är enstaka uttryck. I den här funktionen blir vi av med klammerna och använder = symbol före uttrycket. Med andra ord blir vi av med funktionsblocket.

kul calCircumference (radie: Double): Double return (2 * Math.PI) * radien

Funktionen ovan kan förkortas till en enda linje:

rolig calCircumference (radie: Double) = (2 * Math.PI) * radie

Om du tittar på den uppdaterade funktionen ovan kan du se att vi har gjort vår kod mer koncis genom att ta bort de krökta axlarna , de lämna tillbaka sökord, och även returtypen (som härleds av kompilatorn). 

Du kan fortfarande inkludera returtypen för att vara mer explicit om du vill.

kul calCircumference (radie: Double): Double = (2 * Math.PI) * radie

Namngivna parametrar

Namngivna parametrar tillåter mer läsbara funktioner genom att namnge parametrarna som skickas till en funktion när de kallas.

I följande exempel skapade vi en funktion som skriver ut mitt fullständiga namn.

roligt sayMyFullName (firstName: String, LastName: String, middleName: String): Enhet print ("Mitt fulla namn är $ firstName $ middleName $ lastName"); 

För att utföra funktionen ovan, skulle vi bara kalla det som så:

sayMyFullName ("Chike", "Nnamdi", "Mgbemena")

Om vi ​​tittar på funktionsanropet ovan vet vi inte vilket Sträng typ argument motsvarar vilka funktionsparametrar (även om vissa IDEs som IntelliJ IDEA kan hjälpa oss). Användare av funktionen måste titta på funktions signaturen (eller källkoden) eller dokumentationen för att veta vad varje parameter motsvarar.

sayMyFullName (firstName = "Chike", middleName = "Nnamdi", lastName = "Mgbemena")

I det andra funktionssamtalet ovan gav vi parameternamn före argumentvärdena. Du kan se att detta funktionssamtal är tydligare och mer läsbart än det föregående. Detta sätt att ringa funktioner hjälper till att minska risken för fel som kan hända när argument av samma typ bytas av misstag.

Den som ringer kan också ändra parametervärdena med parametrarna. Till exempel:

sayMyFullName (lastName = "Mgbemena", middleName = "Nnamdi", firstName = "Chike") // kommer fortfarande att kompilera

I koden ovan bytte vi argumentets positionsposition förnamn med efternamn. Argumentordern spelar ingen roll med namngivna parametrar eftersom kompilatorn kommer att kartlägga var och en av dem till den högra funktionsparametern.

Standardparametrar

I Kotlin kan vi ge standardvärden för alla parametrar. Dessa standardvärden används om ingenting tilldelas argumenten under funktionssamtalet. För att göra detta i Java måste vi skapa olika överbelastade metoder.

Här, i vår calCircumference () Metod, vi modifierade metoden genom att lägga till ett standardvärde för pi parameter-Math.PI, en konstant från java.lang.Math paket. 

kul calCircumference (radie: Double, pi: Double = Math.PI): Dubbel = (2 * pi) * radie

När vi kallar den här funktionen kan vi antingen passera vårt approximerade värde för pi eller använd standardvärdet. 

print (calCircumference (24.0)) // använt standardvärde för PI och utskrifter 150.79644737231007 print (calCircumference (24.0, 3.14)) // passerat värde för PI och utskrifter 150.72

Låt oss se ett annat exempel.

roligt utskriftsnamn (firstName: String, middleName: String = "N / A", efternamn: String) println ("förnamn: $ firstName - mellannamn: $ middleName - efternamn: $ lastName")

I följande kod försökte vi ringa funktionen, men den kommer inte att kompilera:

printName ("Chike", "Mgbemena") // kommer inte att kompilera

I funktionssamtalet ovan skickar jag mitt förnamn och efternamn till funktionen och hoppas att använda standardvärdet för mellannamn. Men det här kommer inte att kompilera eftersom kompilatorn är förvirrad. Det vet inte vad argumentet "Mgbemena" är för-är det för mellannamn eller den efternamn parameter? 

För att lösa problemet kan vi kombinera namngivna parametrar och standardparametrar. 

printName ("Chike", lastName = "Mgbemena") // kommer nu att kompilera

Java Interoperabilitet

Med tanke på att Java inte stöder standardparametervärden i metoder måste du ange alla parametervärden uttryckligen när du ringer en Kotlin-funktion från Java. Men Kotlin ger oss funktionaliteten för att underlätta för Java-uppringarna genom att annotera Kotlin-funktionen med @JvmOverloads. Denna anteckning kommer att instruera Kotlin-kompilatorn att generera Java överbelastade funktioner för oss.

I följande exempel annoterade vi calCirumference () fungera med @JvmOverloads.

@JvmOverloads kul calCircumference (radie: Double, pi: Double = Math.PI): Dubbel = (2 * pi) * radie

Följande kod genererades av Kotlin-kompilatorn så att Java-röstare kan välja vilken som ska ringas.

// Java dubbel calCircumference (dubbelradie, dubbel pi); dubbel calCircumference (dubbelradie);

I den senast genererade Java-metoden definitionen, pi parametern utelämnades. Det innebär att metoden kommer att använda standardvärdet pi värde.

Obegränsade argument

I Java kan vi skapa en metod för att ta emot ett ospecificerat antal argument genom att inkludera en ellipsis (... ) efter en typ i metodens parameterlista. Detta koncept stöds också av Kotlins funktioner med hjälp av vararg modifierare följt av parameterns namn.

roligt printInter (vararg in: Int): Enhet för (n in int) print ("$ n \ t") printInts (1, 2, 3, 4, 5, 6) // kommer att skriva ut 1 2 3 4 5 6

De vararg modifieraren tillåter ringer att passera i en kommaseparerad lista över argument. Bakom kulisserna läggs denna lista med argument in i en array. 

När en funktion har flera parametrar, vararg parametern är typiskt den sista. Det är också möjligt att ha parametrar efter vararg, men du måste använda namngivna parametrar för att ange dem när du ringer funktionen. 

roliga printNumbers (myDouble: Double, myFloat: Float, varargint: Int) println (myDouble) println (myFloat) för (n in int) print ("$ n \ t") printNumbers (1.34, 4.4F, 2, 3, 4, 5, 6) // kommer att sammanställa

Till exempel, i koden ovan, parametern med vararg modifieraren är i det sista läget i en multipelparametallista (det här gör vi vanligtvis). Men vad händer om vi inte vill ha det i sista positionen? I följande exempel ligger det i andra läget.

roliga printNumbers (myDouble: Double, vararg int: Int, myFloat: Float) println (myDouble) println (myFloat) för (n in int) print ("$ n \ t") printNumbers (1.34, 2, 3 , 4, 5, 6, myFloat = 4,4F) // kommer kompilera printNumbers (1,34, ints = 2, 3, 4, 5, 6, myFloat = 4,4F) // kommer inte kompilera printNumbers (myDouble = 1.34, ints = 2, 3, 4, 5, 6, myFloat = 4,4F) // kommer inte heller att kompilera

Som du kan observera i den uppdaterade koden ovan använde vi namngivna argument på den sista parametern för att lösa detta.

Spridningsoperatör

Låt oss säga att vi vill skicka en rad heltal till vår printNumbers () fungera. Funktionen förväntar sig att värdena ska rullas in i en lista med parametrar. Om du försöker skicka matrisen direkt till printNumbers (), du ser att den inte kommer att kompilera. 

val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, intsArray, myFloat = 4.4F) // kommer inte att kompilera

För att lösa detta problem måste vi använda spridningsoperatören *. Denna operatör packar upp arrayen och skickar sedan de enskilda elementen som argument till funktionen för oss. 

val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, * intsArray, myFloat = 4.4F) // kommer nu att kompilera

Genom att sätta in spridningsoperatören * framför intsArray I funktionens argumentlista sammanställer koden nu och ger samma resultat som om vi hade passerat elementen i intsArray som en kommaseparerad lista över argument. 

Returnera flera värden

Ibland vill vi returnera flera värden från en funktion. Ett sätt är att använda Par skriv in Kotlin för att skapa en Par och returnera sedan det. Detta Par strukturen omsluter två värden som senare kan nås. Denna Kotlin-typ kan acceptera alla typer du levererar sin konstruktör. Och dessutom behöver de två typerna inte ens vara samma. 

roligt getUserNameAndState (id: Int): Par kräver (id> 0, "Fel: id är mindre än 0") val användarnamn: Karta = mapOf (101 till "Chike", 102 till "Segun", 104 till "Jane") val userStates: Karta = mapOf (101 till "Lagos", 102 till "Imo", 104 till "Enugu") val userName = användarnamn [id] val userState = userStates [id] returnera par (användarnamn, användarstat)

I funktionen ovan konstruerade vi en ny Par genom att passera Användarnamn och userState variabler som första respektive andra argument till dess konstruktör, och returnerade sedan detta Par till den som ringer.

En annan sak att notera är att vi använde en funktion som heter fordra() i getUserNameAndState () fungera. Denna hjälpfunktion från standardbiblioteket används för att ge våra funktionsanropare en förutsättning att träffas, annars en IllegalArgumentException kommer att kastas (vi diskuterar undantag i Kotlin i ett framtida inlägg). Det valfria andra argumentet till fordra() är en funktion som bokstavligen returnerar ett meddelande som ska visas om undantaget kastas. Till exempel, ringa till getUserNameAndState () funktion och passering -1 som ett argument för det kommer att utlösa:

 

Hämtar data från Par

val userNameAndStatePair: Par = getUserNameAndState (101) println (användarnamnAndStatePair.first) // Chike println (userNameAndStatePair.second) // Lagos

I koden ovan öppnade vi de första och andra värdena från Par skriv genom att använda dess först och andra egenskaper.

Det finns dock ett bättre sätt att göra detta: destruktion.

val (namn, stat) = getUserNameAndState (101) println (namn) // Chike println (state) // Lagos

Vad vi har gjort i den uppdaterade koden ovan är att direkt tilldela de första och andra värdena på den returnerade Par skriv till variablerna namn och stat respektive. Den här funktionen heter destruktiva deklarationen.

Triple Return Värden och Beyond

Nu, vad händer om du vill returnera tre värden samtidigt? Kotlin ger oss en annan användbar typ som heter Trippel.

kul getUserNameStateAndAge (id: Int): Triple kräver (id> 0, "id är mindre än 0") val användarnamn: karta = mapOf (101 till "Chike", 102 till "Segun", 104 till "Jane") val userStates: Karta = mapOf (101 till "Lagos", 102 till "Imo", 104 till "Enugu") val userName = användarnamn [id] val userState = userStates [id] val userAge = 6 returnera Triple (användarnamn [id] ], userAge) val (namn, stat, ålder) = getUserNameStateAndAge (101) println (namn) // Chike println (state) // Lagos println (ålder) // 6

Jag är säker på att några av er undrar vad man ska göra om man vill returnera mer än tre värden. Svaret för det kommer att finnas i ett senare inlägg när vi diskuterar Kotlins dataklasser.

Slutsats

I denna handledning lärde du dig om paket och grundläggande funktioner i Kotlins programmeringsspråk. I nästa handledning i Kotlin From Scratch-serien lär du dig mer om funktioner i Kotlin. Ses snart!

För att lära mig mer om Kotlins språket rekommenderar jag att du besöker Kotlins dokumentation. Eller kolla in några av våra andra Android App-utvecklingsposter här på Envato Tuts+!