Inleiding
Gegevenstypes specificeren de soorten waarden die bepaalde variabelen zullen opslaan wanneer je een programma schrijft. Het gegevenstype bepaalt ook welke operaties op de gegevens kunnen worden uitgevoerd.
In dit artikel zullen we de belangrijke gegevenstypes die native zijn in Go behandelen. Dit is geen uitputtende onderzoek naar gegevenstypes, maar zal je helpen vertrouwd te raken met de opties die je in Go ter beschikking hebt. Het begrijpen van enkele basisgegevenstypes zal je in staat stellen duidelijker code te schrijven die efficiënt functioneert.
Achtergrond
Een manier om over gegevenstypes na te denken, is door na te gaan welke soorten gegevens we in de echte wereld gebruiken. Een voorbeeld van gegevens in de echte wereld zijn getallen: we kunnen hele getallen (0, 1, 2, …), gehele getallen (…, -1, 0, 1, …), en irrationale getallen (π) gebruiken, bijvoorbeeld.
Meestal, in de wiskunde, kunnen we getallen van verschillende types combineren en een soort antwoord krijgen. We willen misschien 5 optellen bij π, bijvoorbeeld:
5 + π
We kunnen de vergelijking als antwoord houden om rekening te houden met het irrationale getal, of π afronden naar een getal met een beperkt aantal decimalen, en dan de getallen bij elkaar optellen:
5 + π = 5 + 3.14 = 8.14
Maar, als we beginnen om cijfers te evalueren met een andere datatype, zoals woorden, begint alles minder logisch te klinken. Hoe zouden we de volgende rekeningsreeks oplossen?
shark + 8
Voor computers zijn elk datatype heel verschillend – zoals woorden en cijfers. Daardoor moeten we bij het gebruik van veranderende datatypes voor waarden en hun manipulatie door operaties extra opmerkingen maken.
Integers
In dezelfde manier als in wiskunde zijn integers in programmeer taal hele getallen die positief, negatief of 0 zijn (…, -1, 0, 1, …). In Go wordt een integer bekend als een int
. Zoals in andere programmeer talen, moet je geen komma’s gebruiken bij cijfers van vier of meer digiten, dus schrijf je 1000 in je programma als 1000
.
Je kan een integer simpelweg uitprinten als volgens deze codeblok:
Output-459
Of, je kunt ook een variabeel declareren, wat in dit geval de symbool is van het getal dat je gebruikt of manipuleert, zoals hieronder:
Output-459
We kunnen ook rekenen met integers in Go. In de volgende codeblok zullen we de +
en -
operatoren gebruiken om cijfers te manipuleren:
Output48
Zoals de uitvoer bij de vorige instructie ziet, heeft de mathematicische operator -
het getal 68
van 116
afgehaald, resulterend in 48
. Je leer later meer over variabeeldeclaratie in de Declareren van datatypes voor variabelen sectie.
In Go zijn heel veel mogelijkheden met gebruik van gehele getallen en reëlgetallen binnen een programma. Als je doorgaat met het leren over Go, heb je veel kansen om op basis van deze gegevenssoorten te werken en je kennis over deze data-typen te vergroten.
Decimaal getallen
Een decimaal getal of een float wordt gebruikt om reëlgetallen te representeren die niet als gehele getallen kunnen worden uitgedrukt, zoals 9.0 of -116.42. Voor de doeleinden van het denken over een float in een Go-programma, is het een getal dat een decimaal punt bevat.
Net zoals we gedaan zijn met gehele getallen, kunnen we ook een simpele manier gebruiken om een decimaal getal te printen:
Output-459.67
We kunnen ook een variabele declareren die voor een float staat, zoals hieronder:
Output-459.67
Zoals bij gehele getallen, kunnen we ook reëlgetallen in Go matchen:
Output929.24
Met gehele getallen en decimaal getallen is het belangrijk te beseffen dat 3 != 3.0, omdat 3 een geheel getal betekent terwijl 3.0 een float betekent.
Groottes van numerische types
Naast het onderscheid tussen integers en floats, heeft Go twee soorten numerieke data die worden onderscheiden door de statische of dynamische aard van hun grootte. Het eerste type is een architectuur-onafhankelijk type, wat betekent dat de grootte van de data in bits niet verandert, ongeacht de machine waarop de code draait.
De meeste systeemarchitecturen van vandaag zijn ofwel 32 bit of 64 bit. Bijvoorbeeld, je kunt ontwikkelen voor een moderne Windows laptop, waarop het besturingssysteem draait op een 64-bits architectuur. Als je echter ontwikkelt voor een apparaat zoals een fitnesswatch, werk je misschien met een 32-bits architectuur. Als je een architectuur-onafhankelijk type gebruikt zoals int32
, ongeacht de architectuur waarvoor je compileert, zal het type een constante grootte hebben.
Het tweede type is een implementatie-specifiek type. In dit type kan de bitgrootte variëren op basis van de architectuur waarop het programma is gebouwd. Als we bijvoorbeeld het int
type gebruiken, wanneer Go compileert voor een 32-bits architectuur, zal de grootte van het datatype 32 bits zijn. Als het programma wordt gecompileerd voor een 64-bits architectuur, zal de variabele 64 bits groot zijn.
Naast datatypes met verschillende groottes, komen types zoals integers ook in twee basistypes voor: signed en unsigned. Een int8
is een signed integer, en kan een waarde hebben van -128 tot 127. Een uint8
is een unsigned integer, en kan alleen een positieve waarde hebben van 0 tot 255.
De bereik is gebaseerd op de bitgrootte. Voor binaire gegevens kan een 8-bit integer (int8
) totaal 256 verschillende waarden representeren. Omdat een int
type zowel positieve als negatieve waarden moet ondersteunen, heeft een 8-bit integer (-128 tot 127), voor een totaal van 256 unieke mogelijke waarden.
Go heeft de volgende architectuur-onafhankelijke integer types:
uint8 unsigned 8-bit integers (0 to 255)
uint16 unsigned 16-bit integers (0 to 65535)
uint32 unsigned 32-bit integers (0 to 4294967295)
uint64 unsigned 64-bit integers (0 to 18446744073709551615)
int8 signed 8-bit integers (-128 to 127)
int16 signed 16-bit integers (-32768 to 32767)
int32 signed 32-bit integers (-2147483648 to 2147483647)
int64 signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
Float en complexe getallen komen ook in variënde groottes:
float32 IEEE-754 32-bit floating-point numbers
float64 IEEE-754 64-bit floating-point numbers
complex64 complex numbers with float32 real and imaginary parts
complex128 complex numbers with float64 real and imaginary parts
Er zijn ook enkele alias nummer types, die nuttige namen toevoegen aan specifieke datatypes:
byte alias for uint8
rune alias for int32
De doel van de byte
alias is om te laten blijken wanneer uw programma bytes als een gebruikelijke computermeasurement gebruikt voor karakterstring elementen, in plaats van kleine integers die niet verband houden met de byte data meting. Zelfs alhoewel byte
en uint8
identiek zijn nadat het programma is gecompileerd, wordt byte
vaak gebruikt om karakterdata in numerische vorm te representeren, terwijl uint8
is bedoeld om in uw programma gebruik te maken met cijfers die niet verbonden zijn met de byte data meting.
Het rune
alias is wat anders. Waar byte
en uint8
exact dezelfde zijn, kan een rune
een byte of vier bytes zijn, een bereik definiëren door int32
. Een rune
wordt gebruikt om een Unicode karakter te representeren, terwijl alleen ASCII-karakters door een int32
data type kunnen worden representeerd.
In addition, Go heeft de volgende implementatie-specifieke types:
uint unsigned, either 32 or 64 bits
int signed, either 32 or 64 bits
uintptr unsigned integer large enough to store the uninterpreted bits of a pointer value
Implementatie-specifieke types zullen hun grootte definiëren door de architectuur waarin het programma is gecompileerd.
Kiezen van Numerieke Gegevenstypes
Het kiezen van de juiste grootte heeft meestal meer te maken met de prestaties voor de doelarchitectuur waarvoor je programmeert dan met de grootte van de gegevens waarmee je werkt. Echter, zonder de specifieke gevolgen voor de prestaties van je programma te hoeven kennen, kun je enkele van deze basisrichtlijnen volgen wanneer je net begint.
Zoals eerder in dit artikel besproken, zijn er architectuur-onafhankelijke types en implementatie-specifieke types. Voor integergegevens is het gebruikelijk in Go om de implementatietypes zoals int
of uint
te gebruiken in plaats van int64
of uint64
. Dit zal meestal leiden tot de snelste verwerkingssnelheid voor je doelarchitectuur. Als je bijvoorbeeld een int64
gebruikt en compileert naar een 32-bits architectuur, zal het minstens twee keer zo lang duren om die waarden te verwerken omdat het extra CPU-cycli kost om de gegevens over de architectuur te verplaatsen. Als je in plaats daarvan een int
gebruikt, zou het programma dit definiëren als een 32-bits grootte voor een 32-bits architectuur, en zou het aanzienlijk sneller te verwerken zijn.
Als je weet dat je niet zult overschrijden een specifieke groottebereik, dan kan het kiezen van een architectuur-onafhankelijk type zowel de snelheid verhogen als het geheugengebruik verlagen. Als je bijvoorbeeld weet dat je gegevens niet boven de waarde van 100
zullen uitkomen en alleen positieve getallen zullen zijn, dan zou het kiezen van een uint8
je programma efficiënter maken omdat het minder geheugen vereist.
Nu we hebben enkele mogelijke bereiken voor numerieke gegevenstypen bekeken, laten we eens kijken wat er gebeurt als we deze bereiken in ons programma overschrijden.
Overflow vs. Wraparound
Go heeft de mogelijkheid om zowel een getal te overschrijden als een getal rond te draaien wanneer je probeert een waarde op te slaan die groter is dan het gegevenstype bedoeld was om op te slaan, afhankelijk van of de waarde tijdens het compileren of tijdens runtime wordt berekend. Een compile-time fout treedt op wanneer het programma een fout vindt terwijl het probeert het programma te bouwen. Een runtime fout treedt op nadat het programma is gecompileerd, terwijl het programma daadwerkelijk wordt uitgevoerd.
In het volgende voorbeeld stellen we maxUint32
in op zijn maximale waarde:
Het zal compileren en draaien met het volgende resultaat:
Als we 1
toevoegen aan de waarde tijdens runtime, zal het ronddraaien naar 0
:
Aan de andere kant, laten we het programma wijzigen om 1
toe te voegen aan de variabele wanneer we het toewijzen, vóór het compileren:
Tijdens het compileren, als de compiler kan bepalen dat een waarde te groot zal zijn om op te slaan in het opgegeven gegevenstype, zal het een overflow
fout gooien. Dit betekent dat de berekende waarde te groot is voor het gegevenstype dat je hebt opgegeven.
Omdat de compiler kan bepalen dat het de waarde zal overschrijden, zal het nu een foutmelding geven:
Outputprog.go:6:36: constant 4294967296 overflows uint32
Begrijpen van de grenzen van je data zal je helpen om potentieel fouten in je programma in de toekomst te voorkomen.
Nu we hebben gekeken naar numerieke types, laten we eens kijken hoe we boolean waarden kunnen opslaan.
Booleans
Het boolean datatype kan één van twee waarden hebben, ofwel true
of false
, en wordt gedefinieerd als bool
bij het declareren ervan als een datatype. Booleans worden gebruikt om de waarheidswaarden weer te geven die verband houden met de logica tak van de wiskunde, die algoritmen in de informatica informeren.
De waarden true
en false
zullen altijd met een kleine letter t
en f
respectievelijk worden geschreven, aangezien ze vooraf gedeclareerde identifiers zijn in Go.
Veel operaties in wiskunde geven ons antwoorden die evalueren tot waar of onwaar:
- groter dan
- 500 > 100 true
- 1 > 5 false
- kleiner dan
- 200 < 400 true
- 4 < 2 false
- gelijk
- 5 = 5 true
- 500 = 400 false
Net als bij getallen, kunnen we een boolean waarde opslaan in een variabele:
We kunnen dan de booleaanse waarde afdrukken met een aanroep van de fmt.Println()
functie:
Omdat 5
niet groter is dan 8
, krijgen we het volgende resultaat:
Outputfalse
Naarmate je meer programma’s in Go schrijft, zul je je meer bewust worden van hoe booleans werken en hoe verschillende functies en operaties die resulteren in ofwel true
of false
het verloop van het programma kunnen beïnvloeden.
Strings
Een string is een reeks van een of meer tekens (letters, cijfers, symbolen) die zowel een constante als een variabele kan zijn. Strings bevinden zich in Go binnen zowel enkele aanhalingstekens `
als dubbele aanhalingstekens "
en hebben verschillende eigenschappen afhankelijk van welke aanhalingstekens je gebruikt.
Als je de enkele aanhalingstekens gebruikt, creëer je een onbewerkte string letterlijk. Als je de dubbele aanhalingstekens gebruikt, creëer je een geïnterpreteerde string letterlijk.
Onbewerkte String Letterlijken
Onbewerkte string letterlijken zijn tekenreeksen tussen enkele aanhalingstekens, vaak backticks genoemd. Binnen de aanhalingstekens verschijnen alle tekens precies zoals ze tussen de enkele aanhalingstekens worden weergegeven, met uitzondering van het enkele aanhalingsteken zelf.
OutputSay "hello" to Go!
Meestal worden backslashes gebruikt om speciale tekens in strings weer te geven. Bijvoorbeeld, in een geïnterpreteerde string, zou \n
een nieuwe regel in een string vertegenwoordigen. Echter, backslashes hebben geen speciale betekenis binnen raw string literals:
Omdat de backslash geen speciale betekenis heeft in een string literal, zal het de waarde van \n
daadwerkelijk afdrukken in plaats van een nieuwe regel te maken:
OutputSay "hello" to Go!\n
Raw string literals kunnen ook worden gebruikt om meerregelige strings te creëren:
OutputThis string is on
multiple lines
within a single back
quote on either side.
In de voorgaande codeblokken werden de nieuwe regels letterlijk overgedragen van invoer naar uitvoer.
Geïnterpreteerde String Literals
Geïnterpreteerde string literals zijn reeksen tekens tussen dubbele aanhalingstekens, zoals in "bar"
. Binnen de aanhalingstekens kan elke teken voorkomen, behalve nieuwe regel en ontsnapte dubbele aanhalingstekens. Om dubbele aanhalingstekens in een geïnterpreteerde string weer te geven, kun je de backslash als escape-teken gebruiken, zoals dit:
OutputSay "hello" to Go!
Je zult bijna altijd geïnterpreteerde string literals gebruiken omdat ze het toestaan dat escape-tekens binnenin voorkomen. Voor meer informatie over het werken met strings, bekijk Een Inleiding tot het Werken met Strings in Go.
Strings met UTF-8 Tekens
UTF-8 is een coderingschema dat wordt gebruikt om variabele breedte tekens te coderen in één tot vier bytes. Go ondersteunt UTF-8 tekens standaard, zonder speciale setup, bibliotheken of pakketten. Romeinse tekens zoals de letter A
kunnen worden weergegeven door een ASCII-waarde zoals het getal 65. Met speciale tekens zoals een internationaal teken van 世
is UTF-8 echter vereist. Go gebruikt het rune
alias type voor UTF-8 gegevens.
U kunt het range
trefwoord in een for
loop gebruiken om door elke string in Go te indexeren, zelfs een UTF-8 string. for
loops en range
worden later in de serie uitgebreider besproken; voor nu is het belangrijk om te weten dat we dit kunnen gebruiken om het aantal bytes in een gegeven string te tellen:
In het bovenstaande codeblok hebben we de variabele a
gedeclareerd en de waarde Hello, 世界
eraan toegewezen. De toegewezen tekst bevat UTF-8 tekens.
We hebben vervolgens een standaard for
loop gebruikt evenals het range
trefwoord. In Go zal het range
trefwoord door een string indexeren en één teken tegelijk retourneren, evenals de byte-index waarop het teken zich in de string bevindt.
Met de functie fmt.Printf
hebben we een formaatstring van %d: %s\n
opgegeven. %d
is het printwoord voor een cijfer (in dit geval een geheel getal) en %s
is het printwoord voor een string. Vervolgens hebben we de waarden van i
opgegeven, wat de huidige index is van de for
-lus, en c
, wat het huidige teken in de for
-lus is.
Tot slot hebben we de volledige lengte van de variabele a
afgedrukt door gebruik te maken van de ingebouwde len
functie.
Eerder hebben we vermeld dat een rune een alias is voor int32
en kan bestaan uit één tot vier bytes. Het teken 世
neemt drie bytes in beslag om te definiëren en de index verschuift dienovereenkomstig bij het doorlopen van de UTF-8 string. Dit is de reden dat i
niet sequentieel is wanneer het wordt afgedrukt.
Output0: H
1: e
2: l
3: l
4: o
5: ,
6:
7: 世
10: 界
length of 'Hello, 世界': 13
Zoals je kunt zien, is de lengte langer dan het aantal keren dat het heeft geduurd om over de string te rangeren.
Je werkt niet altijd met UTF-8 strings, maar wanneer je dat wel doet, begrijp je nu waarom ze runes zijn en niet een enkele int32
.
Datatypes Declareren voor Variabelen
Nu je weet wat de verschillende primitieve datatypes zijn, gaan we het behandelen hoe je deze types aan variabelen toewijst in Go.
In Go kunnen we een variabele definiëren met het sleutelwoord var
gevolgd door de naam van de variabele en het gewenste datatype.
In de volgende voorbeeld zal ik een variabele declareren met de naam pi
van het type float64
.
De keyword var
is de eerste ding die wordt gecdeclareerd:
Gevolgd door de naam van onze variabele, pi
:
En uiteindelijk het datatype float64
:
Uw kunnen ook een initiële waarde declareren, zoals bijvoorbeeld 3.14
:
Go is een statisch getypte taal. Statisch getypte betekent dat elke instructie in de programma wordt gecheckt tijdens de compile-tijd. Het betekent ook dat de data-type verbonden is aan de variabele, terwijl in dynamisch gelinkte talen de data-type verbonden is aan de waarde.
Voorbeelden zijn er verschillend bijvoorbeeld in Go en PHP, waar de data-type aan de waarde wordt gebonden:
Elke van deze variabelen kan een andere data-type zijn als je ze declaratief declareert:
Dit is anders dan bijvoorbeeld PHP, waar de data-type aan de waarde wordt gebonden:
In de vorige codeblokken wordt de eerste $s
een string omdat hij de waarde "sammy"
heeft, en de tweede is een integer omdat hij de waarde 123
heeft.
Nu lees je meer over complexe data-typen zoals arrays.
Array’s
Een array is een geordende reeks elementen. De capaciteit van een array wordt bij het aanmaken gedefinieerd. Zodra een array zijn grootte heeft toegewezen, kan de grootte niet meer worden gewijzigd. Omdat de grootte van een array statisch is, betekent dit dat het slechts één keer geheugen toewijst. Dit maakt arrays enigszins rigide om mee te werken, maar verhoogt de prestaties van je programma. Daarom worden arrays doorgaans gebruikt bij het optimaliseren van programma’s. Slices, die hierna worden behandeld, zijn flexibeler en vormen wat je zou denken als arrays in andere talen.
Arrays worden gedefinieerd door de grootte van de array te declareren, gevolgd door het gegevenstype met de waarden gedefinieerd tussen accolades { }
.
Een array van strings ziet er zo uit:
We kunnen een array in een variabele opslaan en uitprinten:
Output[blue coral staghorn coral pillar coral]
Zoals eerder vermeld, zijn slices vergelijkbaar met arrays, maar veel flexibeler. Laten we eens kijken naar dit veranderlijke gegevenstype.
Slices
Een slice is een geordende reeks elementen die van lengte kan veranderen. Slices kunnen hun grootte dynamisch vergroten. Wanneer je nieuwe items aan een slice toevoegt, zal de slice, indien er niet genoeg geheugen is om de nieuwe items op te slaan, indien nodig meer geheugen aanvragen bij het systeem. Omdat een slice kan worden uitgebreid om meer elementen toe te voegen wanneer dat nodig is, worden ze vaker gebruikt dan arrays.
Slices worden gedefinieerd door het gegevenstype te declareren, voorafgegaan door een openings- en sluitingshaakje []
en waarden tussen accolades { }
.
Een slice van integers ziet er zo uit:
Een slice van floats ziet er zo uit:
Een slice van strings ziet er zo uit:
Laten we onze slice van strings definiëren als seaCreatures
:
We kunnen ze uitprinten door de variabele aan te roepen:
De uitvoer zal er precies zo uitzien als de lijst die we hebben gemaakt:
Output[shark cuttlefish squid mantis shrimp]
We kunnen het append
keyword gebruiken om een item aan onze slice toe te voegen. De volgende opdracht voegt de stringwaarde van seahorse
toe aan de slice:
Je kunt verifiëren dat het is toegevoegd door het uit te printen:
Output[shark cuttlefish squid mantis shrimp seahorse]
Zoals je kunt zien, als je een onbekende hoeveelheid elementen moet beheren, zal een slice veel flexibeler zijn dan een array.
Maps
De map is Go’s ingebouwde hash- of dictionarytype. Maps gebruiken keys en values als paar om gegevens op te slaan. Dit is handig in programmeren om snel waarden op te zoeken aan de hand van een index, of in dit geval, een key. Je zou bijvoorbeeld een map van gebruikers kunnen bijhouden, geïndexeerd op hun gebruikers-ID. De key zou de gebruikers-ID zijn en het gebruikersobject zou de waarde zijn. Een map wordt gemaakt door het keyword map
te gebruiken, gevolgd door het key-gegevenstype tussen vierkante haken [ ]
, gevolgd door het waarde-gegevenstype en de key-value paren tussen accolades.
map[key]value{}
Meestal gebruikt om gegevens te bewaren die met elkaar verband houden, zoals de informatie in een ID, ziet een map er zo uit:
Je zult merken dat naast de accolades er ook dubbele punten door de map heen staan. De woorden links van de dubbele punten zijn de sleutels. Sleutels kunnen elk vergelijkbaar type in Go zijn. Vergelijkbare types zijn primitieve types zoals strings
, ints
, enz. Een primitief type wordt gedefinieerd door de taal en is niet gebouwd door andere types te combineren. Hoewel ze door gebruikers gedefinieerde types kunnen zijn, wordt het als beste praktijk beschouwd om ze eenvoudig te houden om programmeerfouten te voorkomen. De sleutels in de bovenstaande dictionary zijn: name
, animal
, color
en location
.
De woorden rechts van de dubbele punten zijn de waarden. Waarden kunnen bestaan uit elk datatype. De waarden in de bovenstaande dictionary zijn: Sammy
, shark
, blue
en ocean
.
Laten we de map in een variabele opslaan en het afdrukken:
Outputmap[animal:shark color:blue location:ocean name:Sammy]
Als we Sammy’s kleur willen isoleren, kunnen we dat doen door sammy["color"]
aan te roepen. Laten we dat afdrukken:
Outputblue
Omdat maps sleutel-waardeparen bieden voor het opslaan van gegevens, kunnen ze belangrijke elementen zijn in je Go-programma.
Conclusie
Op dit punt zou je een beter begrip moeten hebben van enkele van de belangrijkste gegevenstypen die beschikbaar zijn voor je gebruik in Go. Elk van deze gegevenstypen wordt belangrijk wanneer je programmeerprojecten ontwikkelt in de Go-taal.
Zodra je een solide inzicht hebt in de beschikbare gegevenstypen in Go, kun je leren Hoe Gegevenstypen Te Converteren om je gegevenstypen aan te passen aan de situatie.
Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-go