mennä | |
---|---|
Kieliluokka | monisäikeinen , pakottava , jäsennelty , oliosuuntautunut [1] [2] |
Toteutustyyppi | koottu |
Esiintyi | 10. marraskuuta 2009 |
Tekijä | Robert Grismer , Rob Pike ja Ken Thompson |
Kehittäjä | Google , Rob Pike , Ken Thompson , The Go Authors [d] ja Robert Grismer [d] |
Tiedostotunniste _ | .go |
Vapauta |
|
Tyyppijärjestelmä | tiukka , staattinen , tyyppipäätelmällä |
Vaikutettu | C [4] , Oberon-2 , Limbo , Active Oberon , Sequential Process Interaction Theory , Pascal [4] , Oberon [4] , Smalltalk [5] , Newsqueak [d] [6] , Modula-2 [6] , Alef [d] , APL [7] , BCPL , Modula ja Occam |
Lisenssi | BSD |
Verkkosivusto | go.dev _ |
OS | DragonFly BSD , FreeBSD , Linux , macOS , NetBSD , OpenBSD , Plan 9 , Solaris , Microsoft Windows , iOS , Android , AIX ja Illumos |
Mediatiedostot Wikimedia Commonsissa |
Go (usein myös golang ) on käännetty monisäikeinen ohjelmointikieli , jonka Google on kehittänyt sisäisesti [8] . Go:n kehitys alkoi syyskuussa 2007, ja Robert Grismer , Rob Pike ja Ken Thompson [9] , jotka työskentelivät aiemmin Inferno -käyttöjärjestelmän kehitysprojektissa, osallistuivat suoraan sen suunnitteluun . Kieli otettiin käyttöön virallisesti marraskuussa 2009 . Tällä hetkellä tuki kielen tekijöiden kehittämälle viralliselle kääntäjälle tarjotaan käyttöjärjestelmille FreeBSD , OpenBSD , Linux , macOS , Windows , DragonFly BSD , Plan 9 , Solaris , Android , AIX . [10] . Goa tukee myös gcc -kääntäjäjoukko , ja olemassa on useita itsenäisiä toteutuksia. Kielen toista versiota kehitetään.
Googlen valitseman kielen nimi on lähes sama kuin ohjelmointikielen nimi Go! , jonka on luonut F. Gee. McCabe ja C. L. Clark vuonna 2003 [11] . Nimeä käsitellään Go-sivulla [11] .
Kielen kotisivuilla ja yleensä Internet-julkaisuissa käytetään usein vaihtoehtoista nimeä "golang".
Go-kieli kehitettiin ohjelmointikieleksi erittäin tehokkaiden ohjelmien luomiseen, jotka toimivat nykyaikaisissa hajautetuissa järjestelmissä ja moniytimisissä prosessoreissa. Sitä voidaan pitää yrityksenä korvata C- ja C++-kieliä ottaen huomioon muuttuneet tietokonetekniikat ja kertynyt kokemus suurten järjestelmien kehittämisestä [12] . Rob Piken [12] sanoin: "Go on suunniteltu ratkaisemaan Googlen tosielämän ohjelmistokehitysongelmia." Hän mainitsee tärkeimmiksi ongelmiksi seuraavat:
Tärkeimmät kielen vaatimukset olivat [13] :
Go luotiin sillä odotuksella, että siinä olevat ohjelmat käännetään objektikoodiksi ja suoritettaisiin suoraan ilman virtuaalikoneita , joten yksi arkkitehtonisten ratkaisujen valinnan kriteereistä oli kyky varmistaa nopea kääntäminen tehokkaaksi objektikoodiksi ja liiallisen objektikoodin puuttuminen. dynaamisen tuen vaatimukset.
Tuloksena oli kieli, "joka ei ollut läpimurto, mutta oli kuitenkin erinomainen työkalu suurten ohjelmistoprojektien kehittämiseen" [12] .
Vaikka Go:lle on saatavilla tulkki , sille ei käytännössä ole suurta tarvetta, koska käännösnopeus on riittävän nopea vuorovaikutteisen kehityksen mahdollistamiseksi.
Go-kielen [9] pääominaisuudet :
Go ei sisällä monia suosittuja syntaktisia ominaisuuksia, jotka ovat saatavilla muissa nykyaikaisissa sovellusohjelmointikielissä. Monissa tapauksissa tämä johtuu kehittäjien tietoisesta päätöksestä. Lyhyet perustelut valituille suunnittelupäätöksille löytyvät kielen "Usein kysytyistä kysymyksistä" [9] , tarkemmat - kielen sivustolla julkaistuista artikkeleista ja keskusteluista, joissa pohditaan erilaisia suunnitteluvaihtoehtoja. Erityisesti:
Go - kielen syntaksi on samanlainen kuin C - kielen , ja siinä on Oberonista lainattuja elementtejä ja komentosarjakieliä .
Go on kirjainkoon erottelukieli, jossa on täysi Unicode-tuki merkkijonoille ja tunnisteille.
Tunniste voi perinteisesti olla mikä tahansa ei-tyhjä kirjaimia, numeroita ja alaviiva, joka alkaa kirjaimella ja joka ei vastaa mitään Go-avainsanoista. "Kirjaimet" viittaa kaikkiin Unicode-merkkeihin, jotka kuuluvat luokkiin "Lu" (isot kirjaimet), "Ll" (pienet kirjaimet), "Lt" (isot kirjaimet), "Lm" (muokkauskirjaimet) tai " Lo" ( muut kirjaimet), kohdassa "numerot" - kaikki merkit luokasta "Nd" (numerot, desimaalit). Mikään ei siis estä esimerkiksi kyrillin käyttöä tunnisteissa.
Tunnisteet, jotka eroavat toisistaan vain kirjainten osalta, ovat erillisiä. Kielessä on useita käytäntöjä isojen ja pienten kirjainten käytölle. Erityisesti pakettien nimissä käytetään vain pieniä kirjaimia. Kaikki Go-avainsanat kirjoitetaan pienillä kirjaimilla. Isoilla kirjaimilla alkavat muuttujat ovat vietävissä (julkisia), ja pienillä kirjaimilla alkavat muuttujat eivät ole vietävissä (yksityinen).
Merkkijonoliteraalit voivat käyttää kaikkia Unicode-merkkejä ilman rajoituksia. Merkkijonot esitetään UTF-8- merkkijonoina .
Mikä tahansa Go-ohjelma sisältää yhden tai useamman paketin. Paketti, johon lähdekooditiedosto kuuluu, on annettu tiedoston alussa olevasta paketin kuvauksesta. Pakettien nimillä on samat rajoitukset kuin tunnisteilla, mutta ne voivat sisältää vain pieniä kirjaimia. Gorutine-pakettijärjestelmässä on hakemistopuun kaltainen puurakenne. Kaikki globaalit objektit (muuttujat, tyypit, rajapinnat, funktiot, menetelmät, rakenneelementit ja rajapinnat) ovat saatavilla ilman rajoituksia siinä paketissa, jossa ne on ilmoitettu. Globaalit objektit, joiden nimet alkavat isolla kirjaimella, ovat vietävissä.
Jos haluat käyttää toisen paketin viemiä objekteja Go-kooditiedostossa, paketti on tuotava käyttämällä import.
paketin pää /* Tuo */ tuonti ( "fmt" // Vakiopaketti muotoillulle tulosteelle "database/sql" // Tuo sisäkkäinen paketti w "os" // Tuo aliaksella . "math" // Tuo ilman tarkistuksia käytettäessä _ "gopkg.in/goracle.v2" // Paketin koodissa ei ole nimenomaisia viittauksia ) func main () { for _ , arg := range w . Args { // Pääsy "os"-paketissa ilmoitettuun Args-taulukkoon fmt -aliaksen kautta . Println ( arg ) // Paketissa "fmt" määritetyn Println()-funktion kutsuminen paketin nimellä } var db * sql . db = sql . Open ( ajuri , dataSource ) // Sisäkkäisen paketin nimet tarkentuvat // vain itse paketin nimellä (sql) x := Sin ( 1.0 ) // kutsu math.Sin() - tarkennus paketin nimellä math ei tarvita // koska se tuotiin ilman nimeä // Koodissa ei ole viittausta "goracle.v2"-pakettiin, mutta se tuodaan. }Se luettelee lähdepuun src-hakemistosta tuotujen pakettien polut, joiden sijainnin antaa ympäristömuuttuja GOPATH, kun taas vakiopaketeille määritä vain nimi. Paketin tunnistavaa merkkijonoa voi edeltää alias, jolloin sitä käytetään koodissa paketin nimen sijaan. Tuodut objektit ovat saatavilla tiedostossa, joka tuo ne täydellä kelpuutuksella, kuten " пакет.Объект". Jos paketti tuodaan pisteellä aliaksen sijaan, kaikki sen viemät nimet ovat saatavilla ilman rajoituksia. Jotkin järjestelmäapuohjelmat käyttävät tätä ominaisuutta, mutta ohjelmoijan ei suositella sen käyttöä, koska nimenomainen pätevyys tarjoaa suojan nimien törmäyksiltä ja "tuntemattomilta" muutoksilta koodin käyttäytymisessä. Ei ole mahdollista tuoda ilman pätevyyttä kahta samannimistä pakkausta.
Pakettien tuontia Gossa valvotaan tiukasti: jos paketti on tuotu moduulin toimesta, tulee kyseisen moduulin koodissa käyttää vähintään yhtä kyseisen paketin viemää nimeä. Go-kääntäjä käsittelee käyttämättömän paketin tuontia virheenä; tällainen ratkaisu pakottaa kehittäjän pitämään tuontiluettelot jatkuvasti ajan tasalla. Tämä ei aiheuta vaikeuksia, koska Go-ohjelmoinnin tukityökalut (editorit, IDE:t) tarjoavat yleensä automaattisen tuontilistojen tarkistuksen ja päivityksen.
Kun paketti sisältää koodia, jota käytetään vain itsetutkiskelun kautta , on ongelma: tällaisen paketin tuonti on välttämätöntä sen sisällyttämiseksi ohjelmaan, mutta kääntäjä ei salli sitä, koska siihen ei päästä suoraan. _Anonyymi tuonti on mahdollista tällaisissa tapauksissa: " " (yksi alaviiva) on määritetty aliakseksi ; tällä tavalla tuotu paketti käännetään ja sisällytetään ohjelmaan, jos siihen ei ole erikseen viitattu koodissa. Tällaista pakettia ei kuitenkaan voida käyttää nimenomaisesti; Tämä estää tuonnin hallinnan ohittamisen tuomalla kaikki paketit anonyymeinä.
Suoritettavan Go-ohjelman tulee sisältää paketti nimeltä main, jonka tulee sisältää funktio main()ilman parametreja ja palautusarvo. Funktio main.main()on "ohjelman runko" - sen koodi suoritetaan ohjelman käynnistyessä. Mikä tahansa paketti voi sisältää funktion init() - se ajetaan, kun ohjelma ladataan, ennen kuin se alkaa suorittaa, ennen kuin kutsutaan mitään funktiota tässä paketissa ja missä tahansa paketissa, joka tuo sen. Pääpaketti alustetaan aina viimeisenä ja kaikki alustukset tehdään ennen kuin funktio alkaa suorittaa main.main().
Go-pakkausjärjestelmä suunniteltiin olettaen, että koko kehitysekosysteemi on yhtenä tiedostopuuna, joka sisältää kaikkien pakettien ajantasaiset versiot, ja kun uusia versioita ilmestyy, se käännetään kokonaan uudelleen. Sovellusohjelmoinnissa, jossa käytetään kolmannen osapuolen kirjastoja, tämä on melko voimakas rajoitus. Todellisuudessa on usein rajoituksia yhden tai toisen koodin käyttämille pakettien versioille, samoin kuin tilanteita, joissa yhden projektin eri versioissa (haaroissa) käytetään eri versioita kirjastopaketteista.
Versiosta 1.11 lähtien Go on tukenut niin kutsuttuja moduuleja . Moduuli on erityisesti kuvattu paketti, joka sisältää tietoja sen versiosta. Kun moduuli tuodaan, käytetty versio on kiinteä. Tämän avulla koontijärjestelmä voi hallita, täyttyvätkö kaikki riippuvuudet, päivittää tuodut moduulit automaattisesti, kun tekijä tekee niihin yhteensopivia muutoksia, ja estää päivitykset ei-yhteensopiviin versioihin. Moduulien oletetaan olevan ratkaisu (tai paljon helpompi ratkaisu) riippuvuuden hallinnan ongelmaan.
Go käyttää molempia C-tyylisiä kommentteja: upotettuja kommentteja (alkaen // ...) ja estokommentteja (/* ... */). Kääntäjä käsittelee rivikommenttia rivinvaihtona. Lohko, joka sijaitsee yhdellä rivillä - välilyöntinä, useilla riveillä - rivinvaihtona.
Go :n puolipistettä käytetään pakollisena erottimena joissakin toiminnoissa (jos, for, switch). Muodollisesti sen pitäisi myös lopettaa jokainen komento, mutta käytännössä tällaista puolipistettä ei tarvitse laittaa rivin loppuun, koska kääntäjä itse lisää puolipisteet jokaisen rivin loppuun, tyhjiä merkkejä lukuun ottamatta. tunniste, numero, merkkiliteraali, merkkijono, katkaisu, jatka, lasku, palautusavainsanat, lisäys- tai vähennyskomento (++ tai --) tai sulkeva sulkumerkki, neliö tai aaltosulku (tärkeä poikkeus on, että pilkku ei sisälly yllä olevaan luetteloon). Tästä seuraa kaksi asiaa:
Kieli sisältää melko standardin joukon yksinkertaisia sisäänrakennettuja tietotyyppejä: kokonaislukuja, liukulukuja, merkkejä, merkkijonoja, booleaneja ja muutamia erikoistyyppejä.
KokonaisluvutKokonaislukutyyppejä on 11:
Kielen luojat suosittelevat käyttämään vain vakiotyyppiä numeroiden käsittelyyn ohjelman sisällä int. Kiinteän kokoiset tyypit on suunniteltu toimimaan ulkoisista lähteistä vastaanotettujen tai niille välitettyjen tietojen kanssa, kun koodin oikeellisuuden kannalta on tärkeää määrittää tyypin tietty koko. Tyypit ovat synonyymejä byteja runene on suunniteltu toimimaan binääritietojen ja symbolien kanssa. Tyyppiä uintptrtarvitaan vain vuorovaikutukseen ulkoisen koodin kanssa, esimerkiksi C:ssä.
LiukulukuluvutLiukulukuja edustavat kaksi tyyppiä float32ja float64. Niiden koko on 32 ja 64 bittiä, toteutus on IEEE 754 -standardin mukainen . Arvoalueen saa vakiopaketista math.
Numeeriset tyypit rajoittamattomalla tarkkuudellaGo-standardikirjasto sisältää myös paketin big, joka tarjoaa kolme tyyppiä rajattomalla tarkkuudella: big.Int, big.Ratja big.Float, jotka edustavat vastaavasti kokonaislukuja, rationaalilukuja ja liukulukuja; näiden numeroiden koko voi olla mikä tahansa, ja sitä rajoittaa vain käytettävissä olevan muistin määrä. Koska Go:n operaattorit eivät ole ylikuormitettuja, lukujen laskentatoimet rajattoman tarkkuudella toteutetaan tavallisina menetelminä. Suurilla luvuilla suoritettavien laskelmien suorituskyky on tietysti huomattavasti huonompi kuin sisäänrakennetut numeeriset tyypit, mutta tietyntyyppisiä laskentatehtäviä ratkaistaessa paketin bigkäyttö voi olla parempi vaihtoehto kuin matemaattisen algoritmin manuaalinen optimointi.
KompleksiluvutKielessä on myös kaksi sisäänrakennettua tyyppiä kompleksiluvuille complex64ja complex128. Jokainen näiden tyyppien arvo sisältää parin todellisia ja kuvitteellisia osia, joilla on vastaavasti tyypit float32ja float64. Voit luoda koodiin monimutkaisen tyypin arvon kahdella tavalla: joko käyttämällä sisäänrakennettua funktiota complex()tai käyttämällä lausekkeessa imaginaarista literaalia. Voit saada kompleksiluvun reaali- ja imaginaariosat käyttämällä real()ja -funktioita imag().
var x kompleksi128 = kompleksi ( 1 , 2 ) // 1 + 2i y := 3 + 4i // 3 + 4i, 4 on luku, jota seuraa i-liite // on kuvitteellinen fmt -literaali . Println ( x * y ) // tulostaa "(-5+10i)" fmt . Println ( real ( x * y )) // tulostaa "-5" fmt . Println ( imag ( x * y )) // tulostaa "10" Boolen arvotBoolen tyyppi boolon melko yleinen - se sisältää ennalta määritetyt arvot trueja falseosoittavat vastaavasti tosi ja epätosi. Toisin kuin C, Go:n loogiset arvot eivät ole numeerisia eikä niitä voi muuntaa suoraan numeroiksi.
StringsMerkkijonotyyppiarvot stringovat muuttumattomia tavutaulukoita, jotka sisältävät UTF-8. Tämä aiheuttaa useita merkkijonojen erityispiirteitä (esimerkiksi yleisessä tapauksessa merkkijonon pituus ei ole yhtä suuri kuin sitä edustavan taulukon pituus, ts. sen sisältämien merkkien määrä ei ole yhtä suuri kuin numero tavua vastaavassa taulukossa). Useimmissa sovelluksissa, jotka käsittelevät kokonaisia merkkijonoja, tämä erityisyys ei ole tärkeä, mutta tapauksissa, joissa ohjelman on käsiteltävä suoraan tiettyjä riimuja (Unicode-merkkejä), tarvitaan paketti, unicode/utf8joka sisältää aputyökalut Unicode-merkkijonojen kanssa työskentelemiseen.
Kaikille tietotyypeille, myös sisäänrakennetuille, voidaan ilmoittaa uusia analogisia tyyppejä, jotka toistavat kaikki alkuperäisten ominaisuudet, mutta eivät ole yhteensopivia niiden kanssa. Nämä uudet tyypit voivat myös valinnaisesti ilmoittaa menetelmiä. Käyttäjän määrittämiä tietotyyppejä Gossa ovat osoittimet (ilmoitetaan symbolilla *), taulukot (ilmoitetaan hakasulkeilla), rakenteet ( struct), funktiot ( func), liitännät ( interface), kartoitukset ( map) ja kanavat ( chan). Näiden tyyppien ilmoitukset määrittelevät niiden elementtien tyypit ja mahdollisesti tunnisteet. Uudet tyypit ilmoitetaan avainsanalla type:
kirjoita PostString string // Kirjoita "string", samanlainen kuin sisäänrakennettu type StringArray [] string // Taulukkotyyppi merkkijonotyyppisillä elementeillä type Person struct { // Rakennetyypin nimi merkkijono // vakiomerkkijonotyypin kenttä post PostString // aiemmin ilmoitetun mukautetun merkkijonotyypin kenttä bdate aika . Time // kenttä, jonka tyyppi on Time, tuotu paketista aika edate aika . Aikapäällikkö * Henkilö // osoitinkentän päättely [ ]( * Henkilö ) // taulukkokenttä } tyyppi InOutString chan string // kanavatyyppi merkkijonojen välitystä varten tyyppi CompareFunc func ( a , b käyttöliittymä {}) int // funktion tyyppi.Versiosta Go 1.9 lähtien tyyppialiaksien (aliasten) ilmoitus on myös saatavilla:
type TitleString = string // "TitleString" on alias sisäänrakennetulle merkkijonotyypille Integer = int64 // " Integer " on alias sisäänrakennetulle 64-bittiselle kokonaislukutyypilleAlias voidaan ilmoittaa joko järjestelmätyypille tai mille tahansa käyttäjän määrittämälle tyypille. Pohjimmainen ero aliasten ja tavallisten tyyppimääritysten välillä on, että ilmoitus luo uuden tyypin, joka ei ole yhteensopiva alkuperäisen kanssa, vaikka ilmoituksessa ei tehdä muutoksia alkuperäiseen tyyppiin. Alias on vain toinen nimi samalle tyypille, mikä tarkoittaa, että alias ja alkuperäinen tyyppi ovat täysin vaihdettavissa keskenään.
Rakennekentissä voi olla tageja kuvauksessa - mielivaltaiset merkkijonot takalainausmerkkien sisällä:
// Rakenne, jossa on kenttätageja tyyppi XMLInvoices struct { XMLName xml . Nimi `xml:"INVOICES"` Versio int `xml:"version,attr"` Lasku [] * XMLInvoice `xml:"INVOICE"` }Kääntäjä jättää tagit huomioimatta, mutta tiedot niistä sijoitetaan koodiin ja voidaan lukea reflectvakiokirjastoon sisältyvän paketin toimintojen avulla. Tyypillisesti tunnisteita käytetään tyyppijärjestykseen tietojen tallentamiseksi ja palauttamiseksi ulkoiselle medialle tai vuorovaikutukseen ulkoisten järjestelmien kanssa, jotka vastaanottavat tai lähettävät tietoja omissa muodoissaan. Yllä oleva esimerkki käyttää standardin kirjaston käsittelemiä tunnisteita tietojen lukemiseen ja kirjoittamiseen XML-muodossa.
Muuttujien ilmoittamisen syntaksi on pääosin ratkaistu Pascalin hengessä: ilmoitus alkaa avainsanalla var, jota seuraa muuttujan nimi erottimen kautta, sitten erottimen kautta sen tyyppi.
mennä | C++ |
---|---|
var v1 int const v2 merkkijono var v3 [ 10 ] int var v4 [ ] int var v5 rakenne { f int } var v6 * int /* osoittimen aritmetiikkaa ei tueta */ var v7 kartta [ merkkijono ] int var v8 func ( a int ) int | int v1 ; const std :: stringv2 ; _ /* noin */ intv3 [ 10 ] ; int * v4 ; /* noin */ struct { int f ; } v5 ; int * v6 ; std :: unordered_map v7 ; /* noin */ int ( * v8 )( int a ); |
Muuttujan ilmoitus voidaan yhdistää alustukseen:
var v1 int = 100 var v2 string = "Hei!" var v3 [ 10 ] int = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } var v4 [ ] int = { 1000 , 2000 , 12334 } var v5 struct { f int } = 50 } var v6 * int = & v1 var v7 map [ merkkijono ] int = { "yksi" : 1 , "kaksi" : 2 , "kolme" : 3 } var v8 func ( a int ) int = func ( a int ) int { return a + 1 }Jos muuttujaa ei ole nimenomaisesti alustettu sitä määritettäessä, se alustetaan automaattisesti "nolla-arvoon" tietylle tyypille. Nolla-arvo kaikille numeerisille tyypeille on 0, tyypille se string on tyhjä merkkijono, osoittimille se on nil. Rakenteet alustetaan oletusarvoisesti nolla-arvosarjoilla jokaiselle niihin sisältyvälle kentälle, taulukon elementit alustetaan taulukon määrittelyssä määritetyn tyyppisillä nolla-arvoilla.
Mainokset voidaan ryhmitellä:
var ( i int m float )Go - kieli tukee myös automaattista tyyppipäätelmää . Jos muuttuja alustetaan, kun se deklaroidaan, sen tyyppi voidaan jättää pois - sille määritetyn lausekkeen tyypistä tulee muuttujan tyyppi. Literaaleille (numerot, merkit, merkkijonot) kielistandardi määrittelee tietyt sisäänrakennetut tyypit, joihin kukin tällainen arvo kuuluu. Toisen tyyppisen muuttujan alustamiseksi literaaliin on sovellettava eksplisiittinen tyyppimuunnos.
var p1 = 20 // p1 int - kokonaislukuliteraali 20 on tyyppiä int. var p2 = uint ( 20 ) // p2 uint - arvo eksplisiittisesti valettu uint. var v1 = & p1 // v1 *int on osoitin p1:een, jonka int-tyyppi johdetaan. var v2 = & p2 // v2 *uint on osoitin p2:een, joka on nimenomaan alustettu etumerkittömäksi kokonaisluvuksi.Paikallisille muuttujille on lyhennetty ilmoitusmuoto yhdistettynä alustukseen tyyppipäätelmän avulla:
v1 := 100 v2 := "Hei!" v3 := [ 10 ] int { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } v4 := [] int { 1000 , 2000 , 12334 } v5 := }{ struct { f int 50 } v6 := & v1Go käyttää symbolia määritysoperaattorina =:
a = b // Aseta muuttuja a arvoksi bKuten edellä mainittiin, on olemassa tapa määrittää muuttuja automaattisella tyyppipäätelmällä yhdistettynä alustukseen, joka ulkoisesti muistuttaa Pascalin osoitusta :
v1 := v2 // samanlainen kuin var v1 = v2Go-kääntäjä seuraa tarkasti määritelmiä ja määrityksiä ja erottaa ne toisistaan. Koska samannimisen muuttujan uudelleenmäärittely on kielletty yhdessä laajuudessa, yhden koodilohkon sisällä, muuttuja voi esiintyä merkin vasemmalla puolella :=vain kerran:
a := 10 // Kokonaislukumuuttujan ilmoittaminen ja alustaminen a. b := 20 // Kokonaislukumuuttujan ilmoittaminen ja alustaminen b. ... a := b // VIRHE! Yritä määritellä uudelleen a.Go mahdollistaa useiden tehtävien suorittamisen rinnakkain:
i , j = j , i // Vaihda i- ja j-arvot.Tässä tapauksessa tehtävämerkin vasemmalla puolella olevien muuttujien lukumäärän on vastattava täsmälleen tehtävämerkin oikealla puolella olevien lausekkeiden määrää.
Rinnakkaismääritys on myös mahdollista käytettäessä :=. Sen erikoisuus on, että merkin vasemmalla puolella lueteltujen muuttujien :=joukossa voi olla jo olemassa olevia. Tässä tapauksessa luodaan uusia muuttujia, ja olemassa olevia käytetään uudelleen. Tätä syntaksia käytetään usein virheiden käsittelyyn:
x , err := SomeFunction () // Funktio palauttaa kaksi arvoa (katso alla), // kaksi muuttujaa ilmoitetaan ja alustetaan. if ( err != nol ) { return nolla } y , err := SomeOtherFunction () // Vain y ilmoitetaan tässä, err on yksinkertaisesti määritetty arvo.Esimerkin viimeisellä rivillä ensimmäinen funktion palauttama arvo asetetaan uudelle muuttujalle y, toinen jo olemassa olevalle muuttujalle err, jota käytetään koko koodissa kutsuttujen funktioiden palauttaman viimeisen virheen sijoittamiseen. Jos ei tätä operaattorin ominaisuutta :=, toisessa tapauksessa pitäisi ilmoittaa uusi muuttuja (esim. err2) tai erikseen deklaroida yja sitten käyttää tavallista rinnakkaismääritystä.
Go toteuttaa "copy-on-assignment" -semantiikan, mikä tarkoittaa, että tehtävän tuloksena tehdään kopio alkuperäisen muuttujan arvosta ja sijoitetaan tämä kopio toiseen muuttujaan, minkä jälkeen muuttujien arvot ovat erilaisia ja muuttuvat jompaakumpaa ne eivät muuta toista. Tämä pätee kuitenkin vain sisäänrakennetuille skalaarityypeille, rakenteille ja taulukoille, joilla on tietty pituus (eli tyyppejä, joiden arvot on varattu pinoon). Kekoon allokoidaan määrittelemättömän pituisia taulukoita ja kartoituksia , tämän tyyppiset muuttujat sisältävät itse asiassa viittauksia objekteihin, kun niitä määritetään, vain viittaus kopioidaan, mutta ei itse objektia. Joskus tämä voi johtaa odottamattomiin seurauksiin. Harkitse kahta lähes identtistä esimerkkiä:
tyyppi vektori [ 2 ] float64 // Taulukon pituus asetetaan eksplisiittisesti v1 := vector { 10 , 15.5 } // Alustus - v1 sisältää itse taulukon v2 := v1 // Taulukko v1 kopioidaan taulukkoon v2 v2 [ 0 ] = 25.3 // Vaihdettiin vain v2 fmt -taulukko . Println ( v1 ) // Tulostaa "[10 15.5]" - alkuperäinen matriisi ei ole muuttunut. fmt . Println ( v2 ) // Tulostaa "[25.3 15.5]"Tässä tyyppi vectormääritellään kahden luvun taulukoksi. Tällaisten taulukoiden määrittäminen toimii samalla tavalla kuin numeroiden ja rakenteiden määrittäminen.
Ja seuraavassa esimerkissä koodi eroaa täsmälleen yhdellä merkillä: tyyppi vectormääritellään taulukoksi, jonka koko on määrittelemätön. Mutta tämä koodi käyttäytyy täysin eri tavalla:
tyyppi vektori [] float64 // Taulukko määrittelemättömällä pituudella v1 := vektori { 10 , 15.5 } // Alustus - v1 sisältää taulukon viittauksen v2 := v1 // Matriisiviittaus kopioidaan v1:stä v2 :een [ 0 ] = 25.3 / / Voidaan ajatella muuttavan vain v2 fmt - taulukkoa . Println ( v1 ) // Tulostaa "[25.3 15.5]" - alkuperäinen matriisi on MUUTTUNUT! fmt . Println ( v2 ) // Tulostaa "[25.3 15.5]"Kuvaukset ja rajapinnat toimivat samalla tavalla kuin toisessa esimerkissä. Lisäksi, jos rakenteessa on viite- tai rajapintatyyppinen kenttä tai kenttä on dimensioton matriisi tai kartoitus, niin tällaista rakennetta määritettäessä kopioidaan myös vain viittaus, eli eri rakenteiden kentät alkavat. osoittaa samoja kohteita muistissa.
Tämän vaikutuksen välttämiseksi sinun on käytettävä järjestelmätoimintoa copy(), joka takaa objektin toisen esiintymän luomisen.
ilmoitetaan näin:
func f ( i , j , k int , s , t merkkijono ) merkkijono { }Tällaisten arvojen tyypit on suljettu suluissa:
func f ( a , b int ) ( int , merkkijono ) { return a + b , "lisäys" }Toimintojen tulokset voidaan myös nimetä:
func incTwo ( a , b int ) ( c , d int ) { c = a + 1 d = b + 1 paluu }Nimetyt tulokset katsotaan ilmoitetuiksi välittömästi funktion otsikon jälkeen nolla alkuarvolla. Tällaisen funktion return-lausetta voidaan käyttää ilman parametreja, jolloin funktiosta palattuaan tuloksilla on arvot, jotka niille on annettu sen suorituksen aikana. Joten yllä olevassa esimerkissä funktio palauttaa kokonaislukuarvoparin, joka on yksi suurempi kuin sen parametrit.
Useita funktioiden palauttamia arvoja määritetään muuttujille luettelemalla ne pilkuilla eroteltuina, kun taas niiden muuttujien lukumäärän, joille funktiokutsun tulos on määritetty, tulee täsmälleen vastata funktion palauttamien arvojen määrää:
ensimmäinen , toinen := incTwo ( 1 , 2 ) // ensimmäinen = 2, toinen = 3 ensimmäinen := incTwo ( 1 , 2 ) // VÄÄRIN - toiselle tulokselle ei ole määritetty muuttujaaToisin kuin Pascal ja C, joissa paikallisen muuttujan ilmoittaminen käyttämättä sitä myöhemmin tai paikallisen muuttujan arvon menettäminen (kun muuttujalle määritettyä arvoa ei lueta missään) voi aiheuttaa vain kääntäjävaroituksen, Go:ssa tämä tilanne otetaan huomioon. kielivirhe ja johtaa ohjelman kääntämisen mahdottomuuteen. Tämä tarkoittaa erityisesti sitä, että ohjelmoija ei voi jättää huomiotta funktion palauttamaa arvoa (tai yhtä arvoista) yksinkertaisesti kohdistamalla se johonkin muuttujaan ja kieltäytymällä käyttämästä sitä enempää. Jos on tarpeen jättää huomioimatta jokin funktiokutsun palauttamista arvoista, käytetään ennalta määritettyä pseudomuuttujaa nimeltä "_" (yksi alaviiva). Se voidaan määrittää missä tahansa, missä pitäisi olla muuttuja, joka ottaa arvon. Vastaavaa arvoa ei anneta millekään muuttujalle ja se yksinkertaisesti menetetään. Tällaisen arkkitehtonisen päätöksen tarkoitus on tunnistaa käännösvaiheessa mahdollinen laskentatulosten menetys: kääntäjä havaitsee vahingossa tapahtuneen arvonkäsittelyn laiminlyönnin, ja pseudomuuttujan "_" käyttö osoittaa, että ohjelmoija on tietoisesti jättänyt tulokset huomioimatta. Jos seuraavassa esimerkissä tarvitaan vain toinen kahdesta incTwo-funktion palauttamasta arvosta, "_" tulee määrittää toisen muuttujan sijaan:
first := incTwo ( 1 , 2 ) // INVALID first , _ := incTwo ( 1 , 2 ) // TOSI, toista tulosta ei käytetäMuuttuja "_" voidaan määrittää tehtäväluettelossa kuinka monta kertaa tahansa. Kaikki funktiotulokset, jotka vastaavat "_" jätetään huomioimatta.
Viivästetty puhelu korvaa useita syntaktisia ominaisuuksia kerralla, erityisesti poikkeuskäsittelijät ja taatun valmistumisen lohkot. Defer-avainsanalla edeltävä funktiokutsu parametroidaan siinä ohjelman kohdassa, johon se on sijoitettu, ja suoritetaan välittömästi ennen kuin ohjelma poistuu alueesta, jossa se on ilmoitettu, riippumatta siitä, miten ja mistä syystä tämä poistuminen tapahtuu. Jos yksittäinen funktio sisältää useita lykkäysilmoituksia, vastaavat kutsut suoritetaan peräkkäin funktion päätyttyä, käänteisessä järjestyksessä. Alla on esimerkki lykkäyksen käyttämisestä taatun valmistumisen lohkona [15] :
// Funktio, joka kopioi tiedoston func CopyFile ( dstName , srcName string ) ( kirjoitettu int64 , err error ) { src , err := os . Avaa ( srcName ) // Avaa lähdetiedosto if err != nil { // Tarkista return // Jos se epäonnistuu, palaa virheellä } // Jos pääsit tänne, lähdetiedosto avattiin onnistuneesti defer src . Close () // Viivästetty kutsu: src.Close() kutsutaan, kun CopyFile on valmis dst , err := os . Luo ( dstName ) // Avaa kohdetiedosto, jos err != nil { // Tarkista ja palauta virheen palautus } defer dst . Close () // Viivästetty kutsu: dst.Close() kutsutaan, kun CopyFile on valmis paluu . _ Kopioi ( dst , src ) // Kopioi tiedot ja palauta funktiosta // Kun kaikki toiminnot kutsutaan: ensin dst.Close(), sitten src.Close() }Toisin kuin useimmissa kielissä, joissa on C-tyyppinen syntaksi, Go ei sisällä sulkeita ehdollisille rakenteille for, if, switch:
if i >= 0 && i < len ( arr ) { println ( arr [ i ]) } ... for i := 0 ; i < 10 ; minä ++ { } }Go käyttää silmukkarakennetta kaikenlaisten silmukoiden järjestämiseen for.
for i < 10 { // silmukka, jossa on ennakkoehto, samanlainen kuin C } i : = 0 ; i < 10 ; i ++ { // silmukka laskurilla, samanlainen kuin for:ssa C } for { // infinite loop // Silmukasta poistuminen on käsiteltävä manuaalisesti, // yleensä paluu tai tauko } for { // silmukka, jossa on jälkiehto ... // silmukan runko, jos i >= 10 { // poistumisehto katkeaa } } for i , v := alue arr { // silmukka kokoelman (taulukko, viipale, näyttö) läpi arr // i - nykyisen elementin indeksi (tai avain) // v - kopio nykyisen taulukkoelementin arvosta } for i := range arr { // silmukka kokoelman läpi, vain indeksiä käytetään } kohteelle _ , v := range arr { // silmukka kokoelman läpi, käytä vain elementtiarvoja> } for range arr { // Selaa kokoelmaa ilman muuttujia (kokoelmaa käytetään // vain iteraatiolaskurina). } for v := alue c { // silmukka kanavan läpi: // v lukee arvoja kanavasta c, // kunnes kanava sulkee samanaikaisen // gorutiinin }Monivalinta-operaattorin syntaksissa on switchuseita ominaisuuksia. Ensinnäkin, toisin kuin C, operaattorin käyttöä ei vaadita break: kun valittu haara on käsitelty, operaattorin suoritus päättyy. Jos päinvastoin haluat seuraavan haaran jatkavan käsittelyä valitun haaran jälkeen, sinun on käytettävä operaattoria fallthrough:
kytkimen arvo { tapaus 1 : fmt . Println ( "One" ) fallthrough // Seuraavaksi "case 0:" -haara suoritetaan case 0 : fmt . println ( "nolla" ) }Tässä, kun value==1kaksi riviä näytetään, "yksi" ja "nolla".
Vaihtoehtolauseke ja vastaavasti vaihtokäskyn vaihtoehdot voivat olla minkä tyyppisiä tahansa, yhdessä haarassa on mahdollista luetella useita vaihtoehtoja:
vaihtaa merkkiä [ koodi ]. kategoria { tapaus "Lu" , "Ll" , "Lt" , "Lm" , "Lo" : ... tapaus "Nd" : ... oletusarvo : ... }Valintalausekkeen puuttuminen on sallittua, jolloin vaihtoehtoihin tulee kirjoittaa loogiset ehdot. Ensimmäinen haara suoritetaan, jonka ehto on tosi:
switch { case '0' <= c && c <= '9' : return c - '0' case 'a' <= c && c <= 'f' : return c - 'a' + 10 tapaus 'A' <= c && c <= 'F' : paluu c - 'A' + 10 }Tärkeä yksityiskohta: jos yksi ehdolla varustetuista haaroista päättyy operaattoriin fallthrough, tämän haaran jälkeen käsitellään seuraava haara riippumatta siitä, täyttyykö sen ehto . Jos haluat, että seuraava haara käsitellään vain, jos sen ehto täyttyy, sinun on käytettävä peräkkäisiä rakenteita if.
Go-kieli ei tue useimmille moderneille kielille tyypillistä strukturoitua poikkeuskäsittelyn syntaksia , jossa poikkeukset heitetään erityisellä komennolla (yleensä throwtai raise) ja käsitellään lohkossa try-catch. Sen sijaan on suositeltavaa käyttää virheen palautusta yhtenä funktion tuloksena (mikä on kätevää, koska Go-funktiossa funktio voi palauttaa useamman kuin yhden arvon):
Monet kielen kriitikot uskovat, että tämä ideologia on huonompi kuin poikkeusten käsittely, koska lukuisat tarkistukset sotkevat koodia eivätkä salli kaiken virheenkäsittelyn keskittymistä lohkoihin catch. Kielen luojat eivät pidä tätä vakavana ongelmana. Gossa kuvataan useita virheenkäsittelymalleja (katso esimerkiksi Rob Piken artikkeli virallisessa Go-blogissa , venäjänkielinen käännös ), jotka voivat vähentää virheenkäsittelykoodin määrää.
Kun tapahtuu vakavia virheitä, jotka tekevät ohjelman suorittamisen mahdottomaksi (esimerkiksi jako nollalla tai pääsy taulukon rajoihin), syntyy paniikkitila , joka oletusarvoisesti johtaa ohjelman kaatumiseen virheilmoituksen ja puhelupinon jäljityksen kanssa. Paniikki voidaan saada kiinni ja käsitellä käyttämällä deferedellä kuvattua viivästettyjen suoritusten rakennetta. Kohdassa määritetty funktiokutsu defersuoritetaan ennen nykyisestä laajuudesta poistumista, myös paniikkitilanteessa. Kutsutun funktion sisällä defervoit kutsua vakiofunktion recover() - se pysäyttää paniikin järjestelmäkäsittelyn ja palauttaa sen syyn objektin muodossa, errorjoka voidaan käsitellä normaalina virheenä. Mutta ohjelmoija voi myös jatkaa aiemmin saatuaan paniikkiin soittamalla standardiin panic(err error).
// Ohjelma suorittaa ensimmäisen parametrinsa kokonaislukujaon // toisella // ja tulostaa tuloksen. func main () { lykkää toimintaa () { err := palauttaa () if v , ok := err .( error ); ok { // Interface erroria fmt vastaavan paniikin käsittely . Fprintf ( os . Stderr , "Virhe %v \"%s\"\n" , err , v . Error ()) } else if err != nil { paniikki ( err ) // Odottamattomien virheiden käsittely - nosta uudelleen paniikki. } }() a , err := strconv . ParseInt ( os . Args [ 1 ], 10 , 64 ) if err != nil { paniikki ( err ) } b , err := strconv . ParseInt ( os . Args [ 2 ], 10 , 64 ) if err != nil { paniikki ( err ) } fmt . fprintf ( os . Stdout , " %d / %d = %d\n " , a , b , a / b ) }Yllä olevassa esimerkissä voi tapahtua virheitä, kun funktio muuntaa ohjelman argumentit kokonaisluvuiksi strconv.ParseInt(). On myös mahdollista panikoida käytettäessä os.Args-taulukkoa riittämättömällä argumenteilla tai jakattaessa nollalla, jos toinen parametri on nolla. Kaikissa virhetilanteissa syntyy paniikki, joka käsitellään puhelussa defer:
> jaa 105 10/5 = 2 > jaa 10 0 Virhe runtime.errorString "ajonaikainen virhe: kokonaisluku jakaa nolla" > jaa 10,5 2:lla Virhe *strconv.NumError "strconv.ParseInt: jäsennys "10.5": virheellinen syntaksi >jaa 10 Virhe runtime.errorString "ajonaikainen virhe: indeksi alueen ulkopuolella"Paniikkia ei voi laukaista yhdessä rinnakkain suoritettavassa gorutiinissa (katso alla), vaan se voidaan käsitellä toisessa. Ei myöskään ole suositeltavaa "ohjata" paniikkia paketin rajan yli.
Go:n ketjutusmalli periytyi Active Oberon -kielestä Tony Hoaren CSP :n pohjalta käyttäen ideoita Occam- ja Limbo -kielistä [9] , mutta mukana on myös ominaisuuksia, kuten pi-calculus ja kanavointi.
Go antaa sinun luoda uuden ohjelman suoritussäikeen käyttämällä go - avainsanaa , joka suorittaa nimettömän tai nimetyn funktion äskettäin luodussa gorutiinissa (Go-termi korutiinille ). Kaikki saman prosessin goritiinit käyttävät yhteistä osoiteavaruutta, joka suoritetaan käyttöjärjestelmän säikeissä, mutta ilman kovaa sidontaa jälkimmäiseen, mikä sallii käynnissä olevan gorutiinin jättää säikeen estyneen gorutiinin kanssa (jotka odottavat esimerkiksi viestin lähettämistä tai vastaanottamista kanavasta ) ja jatka eteenpäin. Ajonaikainen kirjasto sisältää multiplekserin käytettävissä olevan järjestelmäytimien määrän jakamiseksi gorutiinien kesken. On mahdollista rajoittaa fyysisten prosessoriytimien enimmäismäärää, joilla ohjelma suoritetaan. Go-ajonaikaisen kirjaston gorutiinien itsetuen ansiosta on helppo käyttää suuria määriä gorutiineja ohjelmissa, mikä ylittää huomattavasti järjestelmän tukemien säikeiden lukumäärän rajan.
func server ( i int ) { for { print ( i ) time . Sleep ( 10 ) } } go server ( 1 ) go server ( 2 )Sulkemisia voidaan käyttää go - lausekkeessa .
var g int go func ( i int ) { s := 0 j : = 0 ; j < i ; j ++ { s += j } g = s }( 1000 )Gorutiinien väliseen viestintään käytetään kanavia (sisäänrakennettu tyyppi chan ), joiden kautta mikä tahansa arvo voidaan välittää. Sisäänrakennettu toiminto luo kanavan make(), joka välittää kanavan tyypin ja (valinnaisesti) äänenvoimakkuuden. Oletusarvoisesti kanavan äänenvoimakkuus on nolla. Tällaiset kanavat ovat puskuroimattomia . Voit asettaa minkä tahansa kanavan positiivisen kokonaisluvun äänenvoimakkuuden, jolloin puskuroitu kanava luodaan.
Puskuroimaton putki synkronoi lukijan ja kirjoittajan säikeet tiukasti sitä käyttämällä. Kun kirjoitussäie kirjoittaa jotain putkeen, se pysähtyy ja odottaa, kunnes arvo on luettu. Kun lukijasäie yrittää lukea jotain putkesta, johon on jo kirjoitettu, se lukee arvon ja molemmat säikeet voivat jatkaa suorittamista. Jos kanavalle ei ole vielä kirjoitettu arvoa, lukijaketju pysähtyy ja odottaa jonkun kirjoittavan kanavalle. Toisin sanoen puskuroimattomat putket Gossa käyttäytyvät samalla tavalla kuin Occamin putket tai ada - kielellä kohtaamismekanismi .
Puskuroidulla kanavalla on arvopuskuri, jonka koko on yhtä suuri kuin kanavan koko. Kun kirjoitetaan tällaiseen putkeen, arvo sijoitetaan putken puskuriin ja kirjoitussäie jatkuu ilman taukoa, ellei putken puskuri ole täynnä kirjoitushetkellä. Jos puskuri on täynnä, kirjoitussäie keskeytetään, kunnes vähintään yksi arvo on luettu kanavasta. Lukijalanka lukee myös arvon puskuroidusta putkesta ilman taukoa, jos putken puskurissa on lukemattomia arvoja; jos kanavapuskuri on tyhjä, säie pysähtyy ja odottaa kunnes jokin muu säie kirjoittaa sille arvon.
Kun olet valmis, kanava voidaan sulkea sisäänrakennetulla toiminnolla close(). Yritys kirjoittaa yksityiselle kanavalle aiheuttaa paniikkia, yksityiseltä kanavalta lukeminen tapahtuu aina ilman taukoa ja lukee oletusarvon. Jos kanava on puskuroitu ja se sisältää sulkemishetkellä N aiemmin puskuriin kirjoitettua arvoa, niin ensimmäiset N lukutoimintoa suoritetaan ikään kuin kanava olisi vielä auki ja arvot luetaan puskurista, ja vasta sen jälkeen kanavan lukema palauttaa oletusarvot.
Toimintoa käytetään arvon välittämiseen kanavalle ja kanavalta <-. Kanavalle kirjoitettaessa sitä käytetään binäärioperaattorina, luettaessa - unaarioperaattorina:
in := make ( chan string , 0 ) // Luo puskuroimaton kanava in out := make ( chan int , 10 ) // Luo puskuroitu kanava ulos ... in <- arg // Kirjoita arvo kanavalle ... r1 := <- ulos // lukeminen kanavasta ulos ... r2 , ok := <- ulos // lukeminen, jossa tarkistetaan onko kanava suljettu jos ok { // jos ok == tosi - kanava on auki ... } muuten { // jos kanava on kiinni, tee jotain muuta ... }Kanavan lukemisessa on kaksi vaihtoehtoa: ilman tarkistusta ja kanavan sulkemisen tarkistaminen. Ensimmäinen vaihtoehto (lukee r1 yllä olevassa esimerkissä) yksinkertaisesti lukee seuraavan arvon muuttujaan; jos kanava on suljettu, oletusarvo luetaan kohtaan r1. Toinen vaihtoehto (lukee r2) lukee arvon lisäksi loogisen arvon - ok-kanavan tilalipun, joka on tosi, jos minkä tahansa virran sinne sijoittama data on luettu kanavasta ja epätosi, jos kanava on suljettu ja sen puskuri on tyhjä. Tällä toiminnolla lukijasäie voi määrittää, milloin tulokanava on suljettu.
Lukemista putkesta tuetaan myös käyttämällä for-range loop -rakennetta:
// Funktio aloittaa rinnakkaislukemisen tulokanavasta kokonaislukuina ja kirjoittamisen // lähtökanavalle vain ne kokonaisluvut, jotka ovat positiivisia. // Palauttaa lähtökanavan. func positiiviset ( in <- chan int64 ) <- chan int64 { out := make ( chan int64 ) go func ( ) { // Silmukka jatkuu kunnes kanava sisään suljetaan seuraavalle : = alueelle { if next > 0 { ulos <- seuraava } } sulje ( ulos ) }() palaa ulos }CSP:n lisäksi tai yhdessä kanavointimekanismin kanssa Go mahdollistaa myös tavanomaisen säikeiden synkronoidun vuorovaikutuksen mallin jaetun muistin kautta käyttämällä tyypillisiä pääsyn synkronointityökaluja, kuten mutexeja . Samanaikaisesti kielispesifikaatio kuitenkin varoittaa kaikista yrityksistä synkronoida rinnakkaisten säikeiden vuorovaikutusta jaetun muistin kautta, koska nimenomaisen synkronoinnin puuttuessa kääntäjä optimoi tiedon pääsykoodin ottamatta huomioon mahdollisuutta samanaikaiseen pääsyyn eri lähteistä. säikeitä, mikä voi johtaa odottamattomiin virheisiin. Esimerkiksi arvojen kirjoittaminen globaaleihin muuttujiin yhdessä säikeessä ei välttämättä näy tai näkyy väärässä järjestyksessä rinnakkaissäikeestä.
Harkitse esimerkiksi alla olevaa ohjelmaa. Funktiokoodi main()kirjoitetaan olettaen, että gorutiinissa käynnistetty funktio setup()luo tyypin rakenteen T, alustaa sen merkkijonolla "hello, world" ja antaa sitten viittauksen alustettuun rakenteeseen globaaliin muuttujaan g. B main()aloittaa tyhjän silmukan odottaen gnollasta poikkeavan arvon ilmestymistä. Heti kun se tulee näkyviin, main()tulostaa merkkijonon osoitetusta rakenteesta golettaen, että rakenne on jo alustettu.
kirjoita T struct { viestimerkkijono } _ varg * T _ func setup () { t : = new ( T ) t . msg = "hei, maailma" g = t } func main () { go setup () for g == nil { // EI TOIMI!!! } tulosta ( g . msg ) }Todellisuudessa toinen kahdesta virheestä on mahdollinen.
Ainoa oikea tapa järjestää tiedonsiirto jaetun muistin kautta on käyttää kirjaston synkronointityökaluja, jotka takaavat, että kaikki tiedot, jotka yksi synkronoiduista virroista on kirjoittanut ennen synkronointipistettä, on taatusti saatavilla toisessa synkronoidussa virrassa synkronointipisteen jälkeen.
Go:n monisäikeisyyden ominaisuus on, että gorutiinia ei tunnisteta millään tavalla eikä se ole kieliobjekti, johon voidaan viitata funktioita kutsuttaessa tai joka voidaan sijoittaa säilöön. Näin ollen ei ole olemassa keinoja, joilla voit suoraan vaikuttaa korutiinin suorittamiseen sen ulkopuolelta, kuten keskeyttää ja käynnistää se, muuttaa prioriteettia, odottaa yhden korutiinin valmistumista toisessa ja keskeyttää suorituksen väkisin. Kaikki gorutiiniin kohdistuvat toimet (muu kuin pääohjelman lopettaminen, joka lopettaa automaattisesti kaikki goritiinit) voidaan tehdä vain putkien tai muiden synkronointimekanismien kautta. Seuraavassa on esimerkkikoodi, joka käynnistää useita goutineja ja odottaa niiden valmistumista käyttämällä synkronointijärjestelmäpaketin WaitGroup-synkronointiobjektia. Tämä objekti sisältää laskurin, alun perin nolla, joka voi kasvaa ja pienentää, ja Wait()-menetelmän, joka saa nykyisen säikeen pysähtymään ja odottamaan, kunnes laskuri nollataan.
func main () { var wg sync . WaitGroup // Luo odotusryhmä. Laskurin alkuarvo on 0 logger := log . New ( os . Stdout , "" , 0 ) // log.Logger on säikeen varma tulostustyyppi kohteelle _ , arg := alue os . Args { // Silmukka kaikkien komentorivin argumenttien läpi wg . Lisää ( 1 ) // Kasvata odotusryhmälaskurin arvoa yhdellä // Suorita gorutiini käsitelläksesi arg-parametrin go func ( sanamerkkijono ) { // Odotusryhmälaskurin viivästetty vähentäminen yhdellä. // Tapahtuu, kun toiminto päättyy. lykätä wg . Valmis () loggeri . Println ( readyWord ( word )) // Suorita käsittely ja tulosta tulos }( arg ) } wg . Odota () // Odota, kunnes odotusryhmän wg laskuri on nolla. }Täällä ennen jokaisen uuden gorutiinin luomista objektin wg laskuria kasvatetaan yhdellä ja gorutiinin valmistumisen jälkeen sitä vähennetään yhdellä. Tämän seurauksena silmukassa, joka aloittaa argumenttien käsittelyn, laskuriin lisätään niin monta yksikköä kuin käynnistetään gorutiineja. Kun silmukka päättyy, wg.Wait():n kutsuminen saa pääohjelman pysähtymään. Kun jokainen gorutiini valmistuu, se pienentää wg-laskuria yhdellä, joten pääohjelman odotus päättyy, kun yhtä monta gorutiinia kuin se oli käynnissä, on suoritettu. Ilman viimeistä riviä pääohjelma, joka oli suorittanut kaikki gorutiinit, poistui välittömästi keskeyttäen niiden suorittamisen, joilla ei ollut aikaa suorittaa.
Huolimatta kieleen sisäänrakennetusta monisäikeisyydestä, kaikki vakiokieliobjektit eivät ole säikeen turvallisia. Joten vakiokarttatyyppi (näyttö) ei ole lankaturvallinen. Kielen luojat selittivät tämän päätöksen tehokkuusnäkökohdilla, koska kaikkien tällaisten kohteiden turvallisuuden varmistaminen johtaisi ylimääräisiin kustannuksiin, mikä ei läheskään aina ole välttämätöntä (samat toiminnot kartoitusten kanssa voivat olla osa suurempia operaatioita, jotka ohjelmoija on jo synkronoinut , ja sitten lisäsynkronointi vain vaikeuttaa ja hidastaa ohjelmaa). Versiosta 1.9 alkaen rinnakkaiskäsittelytuen sisältävä synkronointikirjastopaketti on lisännyt säiettä suojaavan sync.Map-tyypin, jota voidaan käyttää tarvittaessa. Voit myös kiinnittää huomiota esimerkissä käytettyyn langankestävään tyyppiin tulosten näyttämiseen log.Logger; sitä käytetään tavallisen fmt-paketin sijaan, jonka toiminnot (Printf, Println ja niin edelleen) eivät ole säikeen turvallisia ja vaatisivat lisäsynkronointia.
Go:ssa ei ole erityistä avainsanaa luokan määrittämiseen, mutta metodit voidaan määrittää mille tahansa nimetylle tyypille, mukaan lukien rakenteet ja kantatyypit, kuten int, joten OOP:ssa kaikki tällaiset tyypit ovat luokkia.
kirjoita newInt intMetodin määrittelysyntaksi on lainattu Oberon-2- kielestä ja eroaa tavallisesta funktion määritelmästä siinä, että func-avainsanan jälkeen suluissa ilmoitetaan ns. "receiver" ( englanniksi vastaanotin ) eli objekti, jolle menetelmää kutsutaan, ja tyyppi, johon menetelmä kuuluu. Kun perinteisissä objektikielissä vastaanotin on implisiittisenä ja sillä on vakionimi (C++:ssa tai Javassa se on "this", ObjectPascalissa se on "itse" jne.), Gossa se on määritelty eksplisiittisesti ja sen nimi voi olla mikä tahansa kelvollinen Go-tunniste.
kirjoita myType struct { i int } // Tässä p on myType-tyypin menetelmien vastaanotin. func ( p * myType ) get ( ) int { return p . i } func ( p * myType ) set ( i int ) { p . minä = minä }Go:ssa ei ole muodollista luokkien (rakenteiden) periytymistä , mutta siinä on teknisesti läheinen upotusmekanismi . Rakenteen kuvauksessa voit käyttää ns. anonyymiä kenttää - kenttää, jolle ei ole ilmoitettu nimeä, vaan vain tyyppiä. Sellaisen kuvauksen seurauksena kaikista upotetun rakenteen elementeistä tulee upotusrakenteen samannimiset elementit.
// Uusi rakennetyypin tyyppi myType2 struct { myType // Nimetön kenttä tarjoaa upotuksen tyyppiä myType. // Nyt myType2 sisältää i-kentän ja get()- ja set(int)-metodit. k int }Toisin kuin klassisessa perinnössä, upotus ei sisällä polymorfista käyttäytymistä (upotusluokan objekti ei voi toimia upotettavan luokan objektina ilman nimenomaista tyyppimuunnosa).
Nimettömälle tyypille ei ole mahdollista ilmoittaa eksplisiittisesti menetelmiä (syntaksi ei yksinkertaisesti salli vastaanottajan tyypin määrittämistä menetelmässä), mutta tämä rajoitus voidaan helposti kiertää sisällyttämällä nimetty tyyppi tarvittavilla menetelmillä.
Luokkapolymorfismi saadaan Go:ssa käyttöliittymien mekanismilla (samanlainen kuin täysin abstrakteja luokkia C++ :ssa ). Rajapinta kuvataan rajapinta-avainsanalla; sisällä (toisin kuin luokkatyyppisissä määrityksissä) kuvaukset ilmoittavat käyttöliittymän tarjoamat menetelmät.
kirjoita myInterface interface { get () int set ( i int ) }Go:ssa ei tarvitse nimenomaisesti ilmoittaa, että tyyppi toteuttaa tietyn rajapinnan. Sen sijaan sääntönä on, että jokaista tyyppiä, joka tarjoaa rajapinnassa määriteltyjä menetelmiä, voidaan käyttää kyseisen rajapinnan toteutuksena. Yllä ilmoitettu tyyppi myTypetoteuttaa rajapinnan myInterface, vaikka sitä ei missään nimenomaisesti mainita, koska se sisältää menetelmiä get()ja set(), joiden allekirjoitukset vastaavat kohdassa kuvattuja myInterface.
Kuten luokat, käyttöliittymät voidaan upottaa:
kirjoita mySecondInterface interface { myInterface // sama kuin eksplisiittisesti deklaroi get() int; set(i int) muuta ( i int ) int }Tässä mySecondInterface-liitäntä perii myInterface-rajapinnan (eli se ilmoittaa paljastavansa myInterfacen sisältämät menetelmät) ja ilmoittaa lisäksi yhden alkuperäisen menetelmän change().
Vaikka Go-ohjelma on periaatteessa mahdollista rakentaa rajapintojen hierarkiaan, kuten muissa objektikielissä tehdään, ja jopa simuloida periytymistä, tätä pidetään huonona käytäntönä. Kieli ei sanele luokka- ja rajapintajärjestelmään hierarkkista, vaan kompositsioonillista lähestymistapaa. Tämän lähestymistavan mukaiset rakenneluokat voivat yleensä pysyä muodollisesti itsenäisinä, eikä rajapintoja yhdistetä yhdeksi hierarkiaksi, vaan ne luodaan tiettyjä sovelluksia varten, tarvittaessa upottamalla olemassa olevia. Liitäntöjen implisiittinen toteutus Gossa tarjoaa näille mekanismeille äärimmäisen joustavuuden ja minimaaliset tekniset vaikeudet niiden käytössä.
Tämä lähestymistapa perintöön on linjassa joidenkin nykyaikaisen ohjelmoinnin käytännön suuntausten kanssa. Joten kuuluisassa kirjassa "neljän jengi" ( Erich Gamma ja muut) erityisesti suunnittelukuvioista kirjoitetaan:
Toteutusriippuvuus voi aiheuttaa ongelmia, kun alaluokkaa yritetään käyttää uudelleen. Jos edes yksi osa vanhasta toteutuksesta ei sovellu uudelle toimialueelle, niin pääluokka on kirjoitettava uudelleen tai korvattava jollakin sopivammalla. Tämä riippuvuus rajoittaa joustavuutta ja uudelleenkäytettävyyttä. Ongelma voidaan ratkaista vain perimällä abstrakteista luokista, koska niillä ei yleensä ole toteutusta tai toteutus on vain vähän.
Go :ssa ei ole käsitettä virtuaalitoiminnosta . Polymorfismin tarjoavat rajapinnat. Jos menetelmän kutsumiseen käytetään tavallisen tyyppistä muuttujaa, niin tällainen kutsu on staattisesti sidottu, eli kutsutaan aina tälle tietylle tyypille määritettyä menetelmää. Jos menetelmää kutsutaan "rajapinta"-tyyppiselle muuttujalle, tällainen kutsu on dynaamisesti sidottu, ja suoritushetkellä menetelmän muunnelma, joka on määritetty kutsumishetkellä tosiasiallisesti osoitetun objektin tyypille. muuttuja valitaan käynnistystä varten.
GOOP- projekti tarjoaa dynaamisen tuen Go:n olio-ohjelmointiin .
Mahdollisuus itsetutkiskeluun ajon aikana, eli kaiken tyyppisten arvojen käyttö ja käsittely sekä dynaaminen säätö käsiteltävien tietotyyppien mukaan, on toteutettu Gossa järjestelmäpaketin avulla reflect. Tämän paketin avulla voit:
Paketti reflectsisältää myös monia aputyökaluja toimintojen suorittamiseen ohjelman dynaamisesta tilasta riippuen.
Matalatason muistin käyttömahdollisuudet on keskitetty järjestelmäpakettiin unsafe. Sen erikoisuus on, että vaikka se näyttää tavalliselta Go-paketilta, se on itse asiassa toteutettu kääntäjällä. Paketti unsafetarjoaa pääsyn tietojen sisäiseen esitykseen ja "oikeisiin" muistiosoittimiin. Se tarjoaa ominaisuuksia:
Paketti tarjoaa myös tyypin unsafe.Pointer, joka voidaan muuntaa mille tahansa osoittimeksi ja joka voidaan muuntaa minkä tahansa tyyppiseksi osoittimeksi, sekä vakiotyyppiseksi uintptr , etumerkittömän kokonaisluvun arvon, joka on riittävän suuri tallentaakseen täyden osoitteen nykyiselle alustalle. Muuttamalla osoittimen muotoon unsafe.Pointerja sitten muotoon uintptr, saat osoitteen kokonaislukuna, johon voit soveltaa aritmeettisia operaatioita. Muuntamalla sitten arvon takaisin unsafe.Pointerosoittimeksi mihin tahansa tiettyyn tyyppiin, pääset tällä tavalla lähes mihin tahansa osoiteavaruuteen.
Kuvatut muunnokset voivat olla vaarallisia, joten niitä suositellaan mahdollisuuksien mukaan välttämään. Ensinnäkin väärän muistialueen virheelliseen käyttöön liittyy ilmeisiä ongelmia. Hienovaraisempi asia on, että paketin käytöstä huolimatta unsafeGo-objekteja hallitsevat edelleen muistinhallinta ja roskakeräys. Osoittimen muuntaminen numeroksi poistaa osoittimen hallinnasta, eikä ohjelmoija voi odottaa tällaisen muunnetun osoittimen pysyvän merkityksellisenä loputtomiin. Esimerkiksi yrittää tallentaa osoittimen uudentyyppiseen objektiin, kuten Тtämä:
pT := uintptr ( unsafe . Osoitin ( uusi ( T ))) // VÄÄRIN!aiheuttaa objektin luomisen ja sen osoitin muunnetaan numeroksi (joka määritetään pT). Sillä on kuitenkin pTkokonaislukutyyppi, eikä roskankerääjä pidä sitä luodun objektin osoittimena, joten kun toiminto on valmis, muistinhallintajärjestelmä pitää tätä objektia käyttämättömänä. Eli roskakeräin voi poistaa sen, minkä jälkeen muunnettu osoitin pTlakkaa. Tämä voi tapahtua milloin tahansa, sekä välittömästi toiminnon päätyttyä että useiden ohjelman toiminnan jälkeen, jolloin virhe ilmenee satunnaisissa ohjelman kaatumisissa, joiden syytä on erittäin vaikea tunnistaa. Ja kun käytetään liikkuvaa roskakerääjää [* 1] , numeroksi muunnetusta osoittimesta voi tulla merkityksetön, vaikka kohdetta ei olisi vielä poistettu muistista.
Koska Go-spesifikaatio ei anna tarkkoja viitteitä siitä, missä määrin ohjelmoija voi odottaa pitävän osoittimen muunnetuna numeroksi, on suositus: pitää tällaiset muunnokset mahdollisimman vähäisinä ja järjestää ne siten, että alkuperäinen osoitin, sen muutokset ja paluumuunnos ovat yhden kielen käskyn sisällä, ja kun kutsut kirjaston funktioita, jotka palauttavat osoitteen muodossa uintptr, muuntaa niiden tuloksen välittömästi muotoon, unsafe.Pointerjotta osoitin ei katoa.
Pakettia unsafekäytetään harvoin suoraan sovellusohjelmoinnissa, mutta sitä käytetään aktiivisesti paketeissa reflect, os, syscall, context, netja joissakin muissa.
On olemassa useita ulkoisia työkaluja, jotka tarjoavat vieraiden toimintojen rajapintoja (FFI) Go-ohjelmille. cgo -apuohjelmaa voidaan käyttää vuorovaikutukseen ulkoisen C -koodin kanssa (tai jolla on C-yhteensopiva liitäntä) . Sitä kutsutaan automaattisesti, kun kääntäjä käsittelee oikein kirjoitetun Go-moduulin, ja varmistaa väliaikaisen Go-käärepaketin luomisen, joka sisältää kaikki tarvittavat tyypit ja toiminnot. C-funktiokutsuissa joudut usein turvautumaan pakettipalveluihin , pääasiassa käyttämällä . Tehokkaampi työkalu on SWIG [16] , joka tarjoaa edistyneempiä ominaisuuksia, kuten integroinnin C++- luokkien kanssa . unsafeunsafe.Pointer
Go-standardikirjasto tukee konsolisovellusten ja verkkopohjaisten palvelinsovellusten rakentamista, mutta asiakassovelluksissa ei ole vakiotyökaluja graafisten käyttöliittymien rakentamiseen. Tämän aukon täyttävät kolmannen osapuolen kääreet suosituille käyttöliittymäkehyksille , kuten GTK+ ja Qt , Windowsissa voit käyttää WinAPI graafisia työkaluja pääsemällä niihin paketin kautta syscall, mutta kaikki nämä menetelmät ovat melko hankalia. Myös itse Gossa on useita UI-kehyksiä kehitettyjä, mutta mikään näistä projekteista ei ole saavuttanut teollisen sovellettavuuden tasoa. Vuonna 2015 GopherCon-konferenssissa Denverissä yksi kielen luojista, Robert Grismer, vastasi kysymyksiin, oli samaa mieltä siitä, että Go tarvitsee käyttöliittymäpaketin, mutta totesi, että tällaisen paketin tulisi olla universaali, tehokas ja monikäyttöinen, mikä tekee sen kehitys pitkä ja vaikea prosessi. Kysymys asiakaskäyttöliittymän käyttöönotosta Gossa on edelleen avoin.
Kielen nuoruudesta johtuen sen kritiikki keskittyy pääasiassa Internet-artikkeleihin, arvosteluihin ja foorumeihin.
Suuri osa kielen kritiikistä keskittyy tiettyjen muiden kielten tarjoamien suosittujen ominaisuuksien puuttumiseen. Heidän joukossaan [17] [18] [19] [20] :
Kuten edellä mainittiin, useiden muilla suosituilla kielillä saatavilla olevien ominaisuuksien puute johtuu kehittäjien tietoisista valinnoista, jotka uskovat, että tällaiset ominaisuudet joko estävät tehokkaan kääntämisen tai provosoivat ohjelmoijaa tekemään virheitä tai luomaan tehottomia tai "huono" koodin ylläpidon kannalta tai niillä on muita ei-toivottuja sivuvaikutuksia.
Kriitikot huomauttavat, että jotkin Go:n ominaisuudet toteutetaan yksinkertaisimmalla tai tehokkaimmalla toteutuksella, mutta ne eivät täytä " vähimmän yllätyksen periaatetta ": niiden käyttäytyminen poikkeaa ohjelmoijan intuition ja aiemman kokemuksen perusteella odottamasta. Tällaiset ominaisuudet vaativat ohjelmoijalta enemmän huomiota, vaikeuttavat oppimista ja vaihtamista muista kielistä.
Usein kritisoidaan automaattisten puolipisteiden mekanismia, jonka vuoksi jotkut lausekkeiden, toimintokutsujen ja listojen kirjoittamisen muodot muuttuvat virheellisiksi. Kommentoimalla tätä päätöstä kielen kirjoittajat huomauttavat [9] , että yhdessä koodinmuodostajan läsnäolon kanssa virallisessa työkalupakkissa gofmtse johti melko jäykän standardin vahvistamiseen Go-koodaukselle. On tuskin mahdollista luoda standardia koodin kirjoittamiselle, joka sopisi kaikille; sellaisen ominaisuuden tuominen kieleen, joka itsessään asettaa tällaisen standardin, yhtenäistää ohjelmien ulkoasun ja eliminoi muotoilusta johtuvat periaatteettomat ristiriidat, mikä on myönteinen tekijä ohjelmistojen ryhmäkehityksessä ja ylläpidossa.
Go:n suosio on kasvanut viime vuosina: vuodesta 2014 vuoteen 2020 Go on noussut 65. sijasta 11 : ksi TIOBE -listalla, elokuun 2020 luokitusarvo on 1,43 %. Dou.ua-tutkimuksen [22] tulosten mukaan Go-kielestä tuli vuonna 2018 yhdeksäs eniten käytettyjen kielten luettelossa ja kuudes niiden kielten luettelossa, joita kehittäjät suosivat henkilökohtaisesti.
Ensimmäisestä julkisesta julkaisusta vuonna 2012 lähtien kielen käyttö on kasvanut tasaisesti. Go-projektin nettisivuilla julkaistu lista teollisessa kehityksessä kieltä käyttävistä yrityksistä sisältää useita kymmeniä nimiä. Eri tarkoituksiin on kertynyt suuri joukko kirjastoja. Version 2.0 julkaisu suunniteltiin vuodelle 2019, mutta työ viivästyi ja jatkuu edelleen vuoden 2022 toisella puoliskolla. Useita uusia ominaisuuksia odotetaan ilmestyvän , mukaan lukien geneeriset sanat ja virheenkäsittelyä yksinkertaistava erityinen syntaksi, joiden puuttuminen on yksi yleisimmistä kielen kriitikoiden valituksista .
RoadRunner (sovelluspalvelin) -verkkopalvelin kehitettiin Golangissa , jonka avulla verkkosovellukset voivat saavuttaa 10-20 ms:n pyyntö-vastausnopeuden perinteisen 200 ms:n sijaan. Tämä verkkopalvelu on suunniteltu sisällytettäväksi suosittuihin kehyksiin, kuten Yii .
C ++ :n ohella Golangia käytetään kehittämään mikropalveluita, joiden avulla voit "kuormata" moniprosessorialustoja työllä. Voit olla vuorovaikutuksessa mikropalvelun kanssa käyttämällä REST -ohjelmaa , ja PHP -kieli on loistava tähän.
Spiral Framework kehitettiin PHP :n ja Golangin avulla. [23]
Itse Go-kielestä on vain yksi pääversio, versio 1. Go-kehitysympäristön versiot (kääntäjä, työkalut ja vakiokirjastot) on numeroitu joko kaksinumeroisina ("<kieliversio>.<pääjulkaisu>") tai kolminumeroinen ("<kieliversio>.< pääjulkaisu>.<alajulkaisu>") järjestelmään. Uuden "kaksinumeroisen" version julkaisu lopettaa automaattisesti edellisen "kaksinumeroisen" version tuen. "Kolminumeroiset" versiot julkaistaan raportoitujen virheiden ja tietoturvaongelmien korjaamiseksi; tällaisten versioiden tietoturvakorjaukset voivat vaikuttaa kahteen viimeiseen "kaksinumeroiseen" versioon [24] .
Kirjoittajat ilmoittivat [25] haluavansa säilyttää mahdollisimman pitkälle taaksepäin yhteensopivuuden kielen pääversiossa. Tämä tarkoittaa, että ennen Go 2:n julkaisua lähes kaikki Go 1 -ympäristössä luodut ohjelmat käännetään oikein missä tahansa myöhemmässä Go 1.x -versiossa ja toimivat ilman virheitä. Poikkeukset ovat mahdollisia, mutta niitä on vähän. Binaariyhteensopivuutta julkaisujen välillä ei kuitenkaan taata, joten ohjelma on käännettävä kokonaan uudelleen, kun siirrytään myöhempään Go-julkaisuun.
Maaliskuun 2012 jälkeen, kun Go 1 esiteltiin, seuraavat suuret versiot on julkaistu:
Kehityksen edistyminen Vuodesta 2017 lähtien on valmisteltu seuraavan kielen perusversion julkaisua, jonka symboli on "Go 2.0" [26] . Kokoelma kommentteja nykyiseen versioon ja muutosehdotuksia, kerätty projektin wikisivustolle [27] . Aluksi oletettiin, että valmisteluprosessi vie "noin kaksi vuotta" ja osa kielen uusista elementeistä sisällytettäisiin seuraaviin Go 1 -version julkaisuihin (tietenkin vain ne, jotka eivät riko taaksepäin yhteensopivuutta ). [26] Huhtikuussa 2021 versio 2.0 ei ole vielä valmis, osa suunnitelluista muutoksista on suunnittelu- ja toteutusvaiheessa. Projektiblogissa [28] hahmoteltujen suunnitelmien mukaan työ suunniteltujen muutosten toteuttamiseksi jatkuu ainakin vuoteen 2021 asti. Ehdotetut innovaatiot Perusinnovaatioita ovat eksplisiittisesti ilmoitetut vakioarvot, uusi virheenkäsittelymekanismi ja yleiset ohjelmointityökalut. Innovaatioprojektit ovat saatavilla verkossa. 28. elokuuta 2018 virallisessa kehittäjäblogissa julkaistiin aiemmin Gophercon 2018 -konferenssissa esitelty video , joka esittelee luonnosversioita uudesta virheenkäsittelysuunnittelusta ja yleisistä toimintojen mekanismista. Suunnitteilla on myös monia vähemmän havaittavissa olevia, mutta erittäin merkittäviä muutoksia [29] , kuten sääntöjen laajentaminen muiden kuin latinalaisten aakkosten tunnisteiden merkkien hyväksymiselle, siirtooperaatioiden salliminen etumerkityille kokonaisluvuille, alaviivan käyttäminen tuhansien ryhmien erottimena. numeroissa, binääriliteraaleissa . Suurin osa niistä on jo otettu käyttöön ja saatavilla Go 1:n uusimmissa versioissa. Käsittelyvirhe Virheenkäsittelymekanismin muuttamiseen harkittiin useita vaihtoehtoja, erityisesti suunnittelua erillisellä virhekäsittelijällä (" Error Handling - Draft Design "). Heinäkuun 2019 viimeinen variantti on kuvattu artikkelissa " Ehdotus: Sisäänrakennettu Go-virheentarkistustoiminto, kokeile ". Tämä vaihtoehto on minimalistisin ja sisältää vain yhden sisäänrakennetun funktion lisäämisen try(), joka käsittelee funktiokutsun tuloksen. Sen käyttöä havainnollistaa alla oleva pseudokoodi . func f ( … )( r1 type_1 , … , rn type_n , err error ) { // Testattu funktio // Palauttaa n+1 tulosta: r1... rn, err of type error. } func g ( … )( … , err error ) { // Kutsu funktio f() virheentarkistuksen kanssa: … x1 , x2 , … xn = try ( f ( … )) // Käytä sisäänrakennettua try:tä: // if f( ) palautti ei-nolla viimeisessä tuloksessa, sitten g() päättyy automaattisesti, // palauttaa saman arvon ITS:n viimeisessä tuloksessa. … } func t ( … )( … , err error ) { // Samanlainen kuin g() ilman uutta syntaksia: t1 , t2 , … tn , te := f ( … ) // Kutsu f() tilapäisesti tallennetuilla tuloksilla muuttujia. if te != nil { // Tarkista yhtälön palautuskoodi nil err = te // Jos paluukoodi ei ole nolla, niin se kirjoitetaan t() viimeiseen tulokseen, return // jonka jälkeen t() päättyy heti. } // Jos virhettä ei ollut, x1 , x2 , … xn = t1 , t2 , … tn // … muuttujat x1…xn saavat arvonsa // ja t():n suoritus jatkuu. … } Toisin sanoen try()se tarjoaa yksinkertaisesti virheentarkistuksen tarkistettavan funktion kutsussa ja välittömän palautuksen nykyisestä funktiosta, jossa on sama virhe. Voit käyttää mekanismia käsittelemään virhettä ennen kuin palaat nykyisestä funktiosta defer. Käyttö try()edellyttää, että sekä tarkistettavalla funktiolla että funktiolla, jossa sitä kutsutaan, on oltava viimeinen tyypin palautusarvo error. Siksi et voi main()käyttää esimerkiksi try(); ylimmällä tasolla kaikki virheet on käsiteltävä erikseen. Tämän virheenkäsittelymekanismin piti olla mukana Go 1.14 :ssä , mutta sitä ei tehty. Käyttöönottopäiviä ei ole määritelty. Yleinen koodi Vuoden 2018 lopussa esiteltiin luonnos yleisistä tyypeistä ja toiminnoista Go:ssa [30] . 9. syyskuuta 2020 julkaistiin tarkistettu suunnitelma [31] , jossa funktioita, tyyppejä ja toimintoparametreja voidaan parametroida parametrityypeillä , joita puolestaan ohjataan rajoituksilla . // Stringer on rajoitusrajapinta, joka vaatii tyypin toteuttamaan // String-metodin, joka palauttaa merkkijonoarvon. kirjoita Stringer - liitäntä { Merkkijono () merkkijono } // Funktio vastaanottaa syötteenä minkä tahansa tyyppisen arvojoukon, joka toteuttaa String-menetelmän, ja palauttaa // vastaavan merkkijonojoukon, joka on saatu kutsumalla String-metodi jokaiselle syöttötaulukon elementille. func Stringify [ T Stringer ] ( s [] T ) [] string { // tyyppiparametri T, jollei Stringer-rajoituksesta, // on taulukkoparametrin s arvotyyppi. ret = make ([] merkkijono , len ( s )) for i , v := alue s { ret [ i ] = v . String () } return ret } ... v := make ([] MyType ) ... // Yleisfunktion kutsumiseksi sinun on määritettävä tietty tyyppi s := Stringify [ String ]( v ) Tässä funktio Stringifysisältää tyyppiparametrin T, jota käytetään tavallisen parametrin kuvauksessa s. Jos haluat kutsua tällaista funktiota, kuten esimerkissä näkyy, sinun on määritettävä kutsussa tietty tyyppi, jota varten sitä kutsutaan. Stringertässä kuvauksessa se on rajoitus , joka vaatii MyTypeä toteuttamaan Stringparametrittoman menetelmän, joka palauttaa merkkijonoarvon. Näin kääntäjä voi käsitellä lausekkeen oikein v.String(). Geneerisen koodin käyttöönotto julkistetaan versiossa 1.18, joka on suunniteltu elokuulle 2021. [28]
Tällä hetkellä Go-kääntäjiä on kaksi:
Hankkeita on myös:
Go-kehitysympäristö sisältää useita komentorivityökaluja: go-apuohjelman, joka tarjoaa käännöksen, testauksen ja pakettien hallinnan, sekä apuohjelmat godoc ja gofmt, jotka on suunniteltu dokumentoimaan ohjelmia ja muotoilemaan lähdekoodia vakiosääntöjen mukaisesti. Jos haluat näyttää täydellisen luettelon työkaluista, sinun on kutsuttava go-apuohjelma ilman argumentteja. Gdb-debuggeria voidaan käyttää ohjelmien virheenkorjaukseen. Riippumattomat kehittäjät tarjoavat suuren määrän työkaluja ja kirjastoja, jotka on suunniteltu tukemaan kehitysprosessia, pääasiassa helpottamaan koodin analysointia, testausta ja virheenkorjausta.
Tällä hetkellä saatavilla on kaksi IDE:tä, jotka ovat alun perin keskittyneet Go-kieleen - tämä on oma GoLand [1] (joka on kehittänyt JetBrains IntelliJ -alustalle) ja ilmainen LiteIDE [2] (aiemmin projektin nimi oli GoLangIDE). LiteIDE on pieni komentotulkki, joka on kirjoitettu C++:lla Qt :llä . Voit kääntää, korjata, muotoilla koodia ja suorittaa työkaluja. Editori tukee syntaksin korostusta ja automaattista täydentämistä.
Goa tukevat myös laajennukset yleisissä IDE:issä Eclipse, NetBeans, IntelliJ, Komodo, CodeBox IDE, Visual Studio, Zeus ja muut. Automaattinen korostus, Go-koodin automaattinen täydennys sekä käynnissä olevat käännös- ja koodinkäsittelyapuohjelmat on toteutettu laajennuksina yli kahdelle tusinalle yleiselle tekstieditorille eri alustoille, mukaan lukien Emacs, Vim, Notepad++, jEdit.
Alla on esimerkki "Hei, maailma!" Go-kielellä.
paketin pääasiallinen tuo "fmt" func main () { fmt . println ( "Hei, maailma!" ) }Esimerkki Unix echo -komennon toteutuksesta :
paketin pääasiallinen tuonti ( "os" "lippu" // komentorivin jäsentäjä ) var omitNewLine = lippu . Bool ( "n" , false , "älä tulosta rivinvaihtoa" ) const ( Space = " " NewLine = "\n" ) func main () { lippu . Parse () // Tarkista argumenttiluettelo ja aseta liput var s string for i := 0 ; minä < lippu . Narg (); i ++ { jos i > 0 { s += Space } s += lippu . Arg ( i ) } jos ! * omitNewLine { s += NewLine } os . Stdout . Kirjoitusjono ( t ) } ![]() | |
---|---|
Temaattiset sivustot | |
Bibliografisissa luetteloissa |
Ohjelmointikielet | |
---|---|
|