Noolemäng vs Swift: võrdlus

Darti logo litsents on antud Creative Commons Attribution 3.0 Unported litsentsi alusel.

Dart ja Swift on minu kaks lemmikprogrammeerimiskeelt. Olen neid laialdaselt kasutanud nii ärilises kui ka avatud lähtekoodiga koodis.

See artikkel pakub Darti ja Swifti võrdlust üksteisega ja selle eesmärk on:

  • Tõstke esile erinevused nende kahe vahel.
  • Olge viide arendajatele, kes liiguvad ühest keelest teise (või kasutavad mõlemat).

Mõni kontekst:

  • Dart annab funktsiooni Flutter, mis on Google'i raamistik kaunite loodusrakenduste loomiseks ühest koodbaasist.
  • Swift annab Apple'i SDK-dele võimaluse iOS, macOS, tvOS ja watchOS.

Järgnev võrdlus on tehtud mõlema keele põhijoonte kohta (Dart 2.1 ja Swift 4.2). Kuna iga funktsiooni põhjalik arutamine ei kuulu selle artikli piiresse, lisan vajaduse korral viited täiendavaks lugemiseks.

Sisukord

  • Võrdlustabel
  • Muutujad
  • Sisestage järeldus
  • Muudetavad / muutumatud muutujad
  • Funktsioonid
  • Nimetud ja nimeta parameetrid
  • Valikulised ja vaikeparameetrid
  • Sulgemine
  • Tuplid
  • Kontrollvool
  • Kollektsioonid (massiivid, komplektid, kaardid)
  • Nullitavus ja valikulised
  • Klassid
  • Pärimine
  • Omadused
  • Protokollid / abstraktsed tunnid
  • Mixins
  • Laiendused
  • Enums
  • Struktuurid
  • Vigade käsitlemisel
  • Geneerikud
  • Juurdepääsu kontroll
  • Asünkroonne programmeerimine: tulevikud
  • Asünkroonne programmeerimine: ojad
  • Mäluhaldus
  • Kompileerimine ja täitmine
  • Muud omadused pole hõlmatud
  • Minu lemmik Swifti funktsioonid puuduvad Dartilt
  • Minu lemmik noolemäng on Swiftilt puudu
  • Järeldus
  • Viited ja krediidid

Võrdlustabel

Muutujad

Muutuva deklaratsiooni süntaks näeb Dartis välja selline:

Stringi nimi;
int vanus;
kahekordne kõrgus;

Ja niimoodi Swiftis:

var nimi: Keel
var vanus: Int
var kõrgus: kahekordne

Muutuv lähtestamine näeb välja selline: Dart:

var nimi = 'Andrea';
var vanus = 34;
var kõrgus = 1,84;

Ja niimoodi Swiftis:

var name = "Andrea"
var vanus = 34
var kõrgus = 1,84

Selles näites pole tüüpi märkusi vaja. Selle põhjuseks on asjaolu, et mõlemad keeled võivad tüüpe tuletada ülesande paremal küljel olevast avaldisest.

Millest rääkides…

Sisestage järeldus

Tüübi järeldamine tähendab, et võime Dart-is kirjutada järgmist:

var argumendid = {'argA': 'tere', 'argB': 42}; // Kaart 

Ja argumentide tüübi lahendab kompilaator automaatselt.

Swiftis võib sama kirjutada järgmiselt:

var argumendid = ["argA": "tere", "argB": 42] // [string: suvaline]

Veel mõned üksikasjad

Darti dokumentatsiooni tsiteerimine:

Analüsaator saab tuletada väljade, meetodite, kohalike muutujate ja kõige üldisemate tüübiargumentide tüüpe. Kui analüsaatoril pole konkreetse tüübi tuletamiseks piisavalt teavet, kasutab see dünaamilist tüüpi.

Ja Swifti jaoks:

Swift kasutab ulatuslikult tüübi järeldusi, lubades teil jätta koodis kasutamata paljude muutujate ja avaldiste tüübi või osa tüübist. Näiteks võite var x: Int = 0 kirjutamise asemel kirjutada var x = 0, jättes tüübi täielikult välja - kompilaator järeldab õigesti, et x nimetab väärtuse Int tüübiks.

Dünaamilised tüübid

Muutuja, mis võib olla mis tahes tüüpi, deklareeritakse dünaamilise märksõnaga jaotises Dart ja mis tahes märksõnaga Swiftis.

Selliste andmete nagu JSON lugemisel kasutatakse tavaliselt dünaamilisi tüüpe.

Muudetavad / muutumatud muutujad

Muutujaid võib kuulutada muutumatuteks või muutumatuteks.

Muutlike muutujate deklareerimiseks kasutavad mõlemad keeled märksõna var.

var a = 10; // int (noolemäng)
a = 20; // Okei
var a = 10 // keskmine (kiire)
a = 20 // ok

Muutumatute muutujate deklareerimiseks kasutab Dart lõplikku ja Swift laseb.

lõplik a = 10;
a = 20; // 'a': lõplik muutuja, seda saab seada ainult üks kord.
las a = 10
a = 20 // Väärtusele ei saa omistada: 'a' on 'lase' konstant

Märkus: Darti dokumentatsioon määratleb kaks märksõna, lõpliku ja const, mis toimivad järgmiselt:

Kui te ei kavatse kunagi muutujat muuta, kasutage lõpliku või const, kas vari asemel või lisaks tüübile. Lõpliku muutuja saab seada ainult üks kord; const muutuja on kompileerimisaja konstant. (Konstantsed muutujad on kaudselt lõplikud.) Lõplik ülataseme või klassi muutuja lähtestatakse esmakordsel kasutamisel.

Lisateavet leiate Darti veebisaidi sellest postitusest:

lõplik tähendab ühekordset ülesannet. Lõplikul muutujal või väljal peab olema initsiaator. Kui väärtus on määratud, ei saa lõpliku muutuja väärtust muuta. lõplik muudab muutujaid.

TL; DR: Dart-i muutumatute muutujate määratlemiseks kasutage lõplikku.

Swiftis kuulutame konstandid lasega. Tsiteerimine:

Pidev deklareerimine tutvustab teie programmis konstantset nime. Pidevad deklaratsioonid deklareeritakse, kasutades märksõna märksõna ja millel on järgmine vorm:
laske konstantsel nimel: tüüp = avaldis
Pidev deklaratsioon määratleb muutumatu sidumise konstantse nime ja initsiaatori avaldise väärtuse vahel; Pärast konstandi väärtuse määramist ei saa seda muuta.

Loe lisaks: Kiirdeklaratsioonid.

Funktsioonid

Funktsioonid on Swift ja Dart esimese klassi kodanikud.

See tähendab, et funktsioone, nagu ka objekte, saab edasi anda argumentidena, salvestada atribuutidena või selle tulemusel tagastada.

Esialgse võrdlusena näeme, kuidas deklareerida funktsioone, millel pole argumente.

Dart-is eelneb tagastamise tüüp meetodi nimele:

tühine foo ();
int bar ();

Swiftis kasutame järelliidetena märget -> T. Seda pole vaja, kui tagasiväärtust pole (Void):

func foo ()
func bar () -> rahvusvaheline

Loe rohkem:

  • Noolemängud
  • Kiirfunktsioonid

Nimetud ja nimeta parameetrid

Mõlemad keeled toetavad nimetamata ja nimeta parameetreid.

Swiftis nimetatakse parameetreid vaikimisi:

func foo (nimi: keelpill, vanus: keskmine, kõrgus: topelt)
foo (nimi: "Andrea", vanus: 34, kõrgus: 1,84)

Dart-is määratleme nimelised parameetrid lokkidega ({}):

void foo ({Stringi nimi, keskmine vanus, topeltkõrgus});
foo (nimi: 'Andrea', vanus: 34, kõrgus: 1,84);

Swiftis määratleme nimeta parameetrid, kasutades välise parameetrina alakriipsu (_):

func foo (_ nimi: keel, _ vanus: keskmine, _ kõrgus: topelt)
foo ("Andrea", 34, 1,84)

Dart-is määratleme nimetamata parameetrid, jättes välja lokirullid ({}):

tühine foo (keelpillinimi, keskmine vanus, topeltkõrgus);
foo ('Andrea', 34, 1,84);

Loe lisaks: Funktsiooni argumentide sildid ja parameetrite nimed Swiftis.

Valikulised ja vaikeparameetrid

Mõlemad keeled toetavad vaikeparameetreid.

Funktsioonis Swift saate funktsiooni mis tahes parameetrile vaikimisi väärtuse määratleda, määrates parameetrile väärtuse pärast selle parameetri tüüpi. Kui vaikimisi väärtus on määratletud, võite funktsiooni helistades selle parameetri jätta.
func foo (nimi: keelpill, vanus: keskmine = 0, kõrgus: kahekordne = 0,0)
foo (nimi: "Andrea", vanus: 34) // nimi: "Andrea", vanus: 34, kõrgus: 0,0

Loe lisaks: Parameetri vaikeväärtused Swiftis.

Dart-režiimis võivad valikulised parameetrid olla kas positsioonilised või nimega, kuid mitte mõlemad.

// positsioonilised valikulised parameetrid
void foo (Stringi nimi, [keskmine vanus = 0, topeltkõrgus = 0,0]);
foo ('Andrea', 34); // nimi: 'Andrea', vanus: 34, kõrgus: 0,0
// nimetatud valikulisteks parameetriteks
tühine foo ({Stringi nimi, keskmine vanus = 0, topeltkõrgus = 0,0});
foo (nimi: 'Andrea', vanus: 34); // nimi: 'Andrea', vanus: 34, kõrgus: 0,0

Lisateave: valikulised parameetrid jaotises Dart.

Sulgemine

Olles esmaklassilised objektid, saab funktsioone anda argumendina teistele funktsioonidele või määrata muutujatele.

Selles kontekstis nimetatakse funktsioone ka sulgemisteks.

Siin on Dart näide funktsioonist, mis itereerib üksuste loendit, kasutades sulgurit iga üksuse registri ja sisu printimiseks:

lõplik nimekiri = ['õunad', 'banaanid', 'apelsinid'];
list.forEach ((element) => print ('$ {list.indexOf (item)}: $ item'));

Sulgemine võtab ühe argumendi (üksuse), prindib selle üksuse indeksi ja väärtuse ning väärtust ei tagastata.

Pange tähele noolemärkide kasutamist (=>). Seda saab kasutada lokirullide sees oleva ühe tagastamise avalduse asemel:

list.forEach ((element) {print ('$ {list.indexOf (item)}: $ item');});

Sama kood Swiftis näeb välja selline:

let list = ["õunad", "banaanid", "apelsinid"]
list.forEach ({print ("\ (string (kirjeldab: list.firstIndex (of: 0 $)))) \ ($ 0)")})

Sel juhul ei täpsusta me sulgemisele edastatud argumendi nime ja kasutame esimese argumendi asemel 0 dollarit. See on täiesti vabatahtlik ja võime kasutada nimega parameetrit, kui eelistame:

list.forEach ({üksus trükis ("\ (string (kirjeldab: list.firstIndex (of: item)))) \ (item)")})

Sulgemisi kasutatakse Swiftis sageli asünkroonse koodi lõpetamisplokkidena (asünkroonse programmeerimise kohta lugege allpool olevat jaotist).

Loe rohkem:

  • Noolemäng anonüümsed funktsioonid
  • Kiire sulgemine

Tuplid

Swift Docsist:

Tuples rühmitab mitu väärtust üheks liitväärtuseks. Paaris olevad väärtused võivad olla mis tahes tüüpi ja ei pea olema üksteisega sama tüüpi.

Neid saab kasutada väikeste kergtüüpidena ja need on kasulikud mitme tagasiväärtusega funktsioonide määratlemisel.

Siit saate teada, kuidas kasutada kiirkorraldusi Swiftis:

laske t = ("Andrea", 34, 1,84)
print (t.0) // prindib "Andrea"
print (t.1) // prindib 34
print (t.2) // prindib 1.84

Tuppe toetatakse Dartis eraldi paketiga:

const t = const Tuple3  ('Andrea', 34, 1,84);
trükkida (t.item1); // prindib 'Andrea'
print (t.item2); // prindib 34
print (t.item3); // prindib 1,84

Kontrollvool

Mõlemad keeled pakuvad mitmesuguseid juhtimisvoo avaldusi.

Selle näideteks on, kui tinglikud, silmustes ja nende ajal vahetavad avaldusi.

Nende käsitlemine siin oleks üsna pikk, nii et viitan ametlikele dokumentidele:

  • Kiire juhtimisvool
  • Dart Controli voolavused

Kollektsioonid (massiivid, komplektid, kaardid)

Massiivid / nimekirjad

Massiivid on järjestatud objektide rühmad.

Massiive saab luua loenditena noolemängus:

var emptyList =  []; // tühi nimekiri
var loend = [1, 2, 3]; // nimekiri sõnasõnaline
loetelu.pikkus; // 3
nimekiri [1]; // 2

Massiividel on Swiftis sisseehitatud tüüp:

var emptyArray = [Int] () // tühi massiiv
var massiiv = [1, 2, 3] // massiivi sõnasõnaline
array.count // 3
massiiv [1] // 2

Komplektid

Tsiteerides Swifti dokumente:

Komplekt salvestab kollektsioonis sama tüüpi erinevad väärtused, millel pole määratletud tellimust. Kui üksuste järjekord pole oluline või kui peate tagama, et üksus ilmub ainult üks kord, võite massiivi asemel kasutada komplekti.

Seda määratletakse Dart-i klassiga Set.

var emptyFruits =  {}; // tühi komplekt sõnasõnaline
var puuviljad = {'õun', 'banaan'}; // seadke sõnasõnaline

Samuti Swiftis:

var emptyFruits = Määra  ()
var puuviljad = määra  (["õun", "banaan"])

Kaardid / sõnaraamatud

Swifti dokumentidel on hea määratlus kaardil / sõnaraamatul:

Sõnaraamat salvestab seosed sama tüüpi võtmete ja sama tüüpi väärtuste vahel kogumis ilma määratletud järjestuseta. Iga väärtus on seotud unikaalse võtmega, mis toimib selle väärtuse identifikaatorina sõnastikus.

Kaardid on määratletud nii nagu Dartis:

var namesOfIntegers = Kaart  (); // tühi kaart
var lennujaamad = {'YYZ': 'Toronto Pearson', 'DUB': 'Dublin'}; // kaardi sõnasõnaline

Kaardid on Swiftis sõnaraamatuteks:

var namesOfIntegers = [Int: String] () // tühi sõnastik
var lennujaamad = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] // sõnastiku sõnaraamat

Loe rohkem:

  • Noolemängu kogud
  • Swifti kogud (eriti soovitan sektsiooni komplektide kohta).

Nullitavus ja valikulised

Dartis võib iga objekt olla olematu. Ja proovides juurdepääsu nullobjektide meetoditele või muutujatele, saadakse nullkursori erand. See on üks levinumaid vigade allikaid (kui mitte kõige levinum) arvutiprogrammides.

Algusest peale oli Swiftil valikulisi võimalusi, sisseehitatud keelefunktsioon, mis võimaldas kuulutada, kas objektidel on väärtus või mitte. Dokumentide tsiteerimine:

Kasutate valikulisi olukordades, kus mõni väärtus võib puududa. Valikuline tähistab kahte võimalust: kas väärtus on olemas ja selle väärtuse juurde pääsemiseks võite selle lahti pakkida, või pole väärtust üldse.

Vastupidiselt sellele võime kasutada valikulisi muutujaid, et tagada nende väärtus alati:

var x: Int? // valikuline
var y: Int = 1 // valikuline, tuleb lähtestada

Märkus: ütlus, et Swifti muutuja on valikuline, on umbes sama, mis öelda, et Dart muutuja võib olla null.

Ilma valikuliste keeletaset toeta saame tööajas kontrollida ainult siis, kui muutuja on null.

Valikuliste abil kodeerime selle teabe kompileerimise ajal. Saame valikud lahti võtta, et kontrollida ohutult, kas neil on väärtus:

func showValikuline (x: Int?) {
  // parimate tavadena kasutage sõna "valve let", mitte "if let"
  kui lasta x = x {// lahti pakkida valikuline
    prindi (x)
  } veel {
    print ("väärtus puudub")
  }
}
showOptiline (x: null) // prindib "väärtus puudub"
showOptsiooniline (x: 5) // prindib "5"

Ja kui me teame, et muutujal peab olema väärtus, võime kasutada valikulist:

func showNonOptional (x: Int) {
  prindi (x)
}
showNonOptional (x: null) // [kompileerimisviga] Null ei ühildu eeldatava argumenditüübiga „Int”
showNonOptional (x: 5) // prindib "5"

Esimest ülaltoodud näidet saab Dartis rakendada nii:

tühine showValikuline (int x) {
  if (x! = null) {
    print (x);
  } veel {
    print ('väärtus puudub');
  }
}
showOptsiooniline (null) // prindib "väärtus puudub"
showOptsiooniline (5) // prindib numbri "5"

Ja teine ​​selline:

void showNonOptional (int x) {
  väita (x! = null);
  print (x);
}
showNonOptional (null) // [käitustõrge] Tagastamata erand: kinnitamine nurjus
showNonOptional (5) // prindib "5"

Valikuliste olemasolu tähendab, et vigu saame püüda kompileerimise ajal, mitte käitusel. Ja vigade varakult tabamine annab turvalisema koodi vähem veateatega.

Darti valikuliste toe puudumist leevendab kuidagi väidete kasutamine (ja nimetatud parameetrite @ nõutav märkus).

Neid kasutatakse laialdaselt Flutter SDK-s, kuid tulemuseks on täiendav katlamaja kood.

Rekordi jaoks on olemas ettepanek lisada Dart-i mittetühjendatavaid tüüpe.

Valikulisi on palju rohkem, kui ma siin käsitletud olen. Hea ülevaate saamiseks vaadake: Valikud Swiftis.

Klassid

Klassid on peamiseks objektiks orienteeritud keeltes programmide kirjutamisel.

Klasse toetavad Dart ja Swift, mõnede erinevustega.

Süntaks

Siin on klass algataja ja kolme liikmelise muutujaga Swiftis:

klassi inimene {
  lase nimi: Keel
  las vanus: Int
  laskmise kõrgus: kahekordne
  init (nimi: keelpill, vanus: keskmine, kõrgus: kahekordne) {
    ise.nimi = nimi
    self.age = vanus
    ise.kõrgus = kõrgus
  }
}

Ja sama on ka Dartis:

klassi inimene {
  Isik ({see.nimi, see.age, see.kõrgus});
  lõplik keelsenimi;
  lõplik keskmine vanus;
  lõplik topeltkõrgus;
}

Pange tähele selle kasutamist. [PropertyName] Dart-konstruktoris. See on süntaktiline suhkur esinemisliikmete muutujate seadistamiseks enne konstrukatori käivitamist.

Vabriku konstruktorid

Dartis on võimalik luua tehasekonstruktoreid. Tsiteerimine:

Kasutage tehase märksõna, kui rakendate konstruktorit, mis ei loo alati oma klassist uut eksemplari.

Üks tehasekonstruktorite praktiline kasutusjuhtum on JSONist mudeliklassi loomisel:

klassi inimene {
  Isik ({see.nimi, see.age, see.kõrgus});
  lõplik keelsenimi;
  lõplik keskmine vanus;
  lõplik topeltkõrgus;
  tehas Person.fromJSON (kaart  json) {
    Stringi nimi = json ['nimi'];
    int age = json ['vanus'];
    topeltkõrgus = json ['kõrgus'];
    tagasi isik (nimi: nimi, vanus: vanus, kõrgus: kõrgus);
  }
}
var p = Person.fromJSON ({
  'nimi': 'Andrea',
  'vanus': 34,
  'kõrgus': 1,84,
});

Loe rohkem:

  • Noolemängu klassid
  • Kiirkonstruktsioonid ja klassid

Pärimine

Swift kasutab ühe pärimise mudelit, mis tähendab, et igal klassil võib olla ainult üks superklass. Swift-klassid võivad rakendada mitmeid liideseid (tuntud ka kui protokollid).

Noolemänguklassidel on seguinipõhine pärand. Dokumentide tsiteerimine:

Iga objekt on klassi näide ja kõik klassid põlvnevad objektist. Mixini-põhine pärand tähendab, et kuigi igal klassil (välja arvatud objekt) on täpselt üks superklass, saab klassi keha korduvalt kasutada mitme klassi hierarhias.

Siin on ühekordne pärand tegevus Swiftis:

klassi sõiduk {
  let wheelCount: Int
  init (rattaarv: Int) {
    self.wheelCount = wheelCount
  }
}
klassi jalgratas: sõiduk {
  selles() {
    super.init (rataste arv: 2)
  }
}

Ja Dartis:

klassi sõiduk {
  Sõiduk ({this.wheelCount});
  lõplik keskmine ratasarv;
}
klassi jalgratas laiendab sõidukit {
  Jalgratas (): super (rataste arv: 2);
}

Omadused

Neid nimetatakse Dartis esinemismuutujateks ja Swiftis lihtsalt omadusteks.

Swiftis tehakse vahet salvestatud ja arvutatud omaduste vahel:

klassi ring {
  init (raadius: topelt) {
    self.radius = raadius
  }
  lase raadius: Topelt // salvestatud atribuut
  var läbimõõt: topelt {// ainult lugemiseks arvutatud omadus
    tagasisõiduraadius * 2.0
  }
}

Dartis on meil sama erinevus:

klassi ring {
  Ring ({this.radius});
  lõplik topeltraadius; // salvestatud vara
  kahekordne läbimõõt => raadius * 2,0; // arvutatud omadus
}

Lisaks arvutatud omaduste getteritele saame määratleda ka setterid.

Ülaltoodud näite abil võime diameetri omaduse ümber kirjutada, et lisada setter:

var läbimõõt: topelt {// arvutatud omadus
  saada {
    tagasisõiduraadius * 2.0
  }
  sea ​​{
    raadius = newValue / 2.0
  }
}

Dartis saame lisada eraldi setteri näiteks:

seatud läbimõõt (kahekordne väärtus) => raadius = väärtus / 2,0;

Kinnisvaravaatlejad

See on Swifti eripära. Tsiteerimine:

Kinnisvaravaatlejad jälgivad kinnisvara väärtuse muutusi ja reageerivad neile. Kinnisvaravaatlejateks kutsutakse iga kord, kui vara väärtus seatakse, isegi kui uus väärtus on sama kui vara praegune väärtus.

Neid saab kasutada järgmiselt:

var läbimõõt: topelt {// ainult lugemiseks arvutatud omadus
  willSet (newDiameter) {
    print ("vana väärtus: \ (läbimõõt), uus väärtus: \ (newDiameter)")
  }
  didSet {
    print ("vana väärtus: \ (vana väärtus), uus väärtus: \ (läbimõõt)")
  }
}

Loe rohkem:

  • Dart astme muutujad, getterid ja setterid
  • Swifti omadused

Protokollid / abstraktsed tunnid

Siin räägime konstruktist, mida kasutatakse meetodite ja omaduste määratlemiseks, täpsustamata nende rakendamist. Teistes keeltes nimetatakse seda liideseks.

Swiftis nimetatakse liideseid protokollideks.

protokolli kuju {
  func ala () -> kahekordne
}
klassi ruut: kuju {
  lase külg: topelt
  init (külg: topelt) {
    ise.külg = külg
  }
  func area () -> Double {
    tagakülg * külg
  }
}

Dartil on sarnane konstruktsioon, mida tuntakse abstraktse klassina. Abstraktseid tunde ei saa kohe muuta. Nad saavad siiski määratleda meetodeid, millel on rakendus.

Ülaltoodud näite saab Dartis kirjutada nii:

abstraktne klassi kuju {
  topeltpiirkond ();
}
klassi väljak laiendab kuju {
  Ruut ({this.side});
  lõplik kahepoolne külg;
  topeltpiirkond () => külg * külg;
}

Loe rohkem:

  • Kiirprotokollid
  • Noolemängutreeningu tunnid

Mixins

Dartis on mixin lihtsalt tavaline klass, mida saab korduvalt kasutada mitme klassi hierarhias.

Nii saaksime laiendada varem defineeritud Isikuklassi segukomplektiga NameExtension:

abstraktne klass NameExtension {
  String saada nimi;
  String saada suur tähtNimi => nimi.toUpperCase ();
  String saada väiketähtNimi => nimi.toLowerCase ();
}
klassi isik, kelle nimi on laiendatud {
  Isik ({see.nimi, see.age, see.kõrgus});
  lõplik keelsenimi;
  lõplik keskmine vanus;
  lõplik topeltkõrgus;
}
var inimene = Isik (nimi: 'Andrea', vanus: 34, pikkus: 1,84);
print (person.uppercaseName); // 'ANDREA'

Loe lisaks: Dart Mixins

Laiendused

Laiendid on Swifti keele tunnusjoon. Dokumentide tsiteerimine:

Laiendid lisavad olemasolevale klassile, struktuurile, loendile või protokolli tüübile uut funktsionaalsust. See hõlmab võimalust laiendada tüüpe, millele teil pole juurdepääsu algsele lähtekoodile (tuntud kui tagasiulatuv modelleerimine).

Dartis pole see segude puhul võimalik.

Laenustades ülaltoodud näidet, võime laiendada klassi Isik nii:

laiend Isik {
  var uppercaseName: string
    tagasinimi.superkallatud ()
  }
  var smallcaseName: string
    tagasinimi.lõigatud ()
  }
}
var inimene = Isik (nimi: "Andrea", vanus: 34, pikkus: 1,84)
print (person.uppercaseName) // "ANDREA"

Laiendusi on palju rohkem, kui ma siin esitlenud olen, eriti kui neid kasutatakse koos protokollide ja geneeriliste ravimitega.

Üks väga levinud laiendite kasutamise juhtum on protokollile vastavuse lisamine olemasolevatele tüüpidele. Näiteks saame laiendi kasutada olemasolevale mudeliklassile serialiseerimisvõimaluste lisamiseks.

Loe lisaks: Kiirlaiendid

Enums

Dartil on enumide jaoks väga lihtne tugi.

Swifti enumid on väga võimsad, kuna need toetavad seotud tüüpe:

enum NetworkResponse {
  juhtumi edu (sisu: Andmed)
  juhtumi rike (tõrge: viga)
}

See võimaldab loogikat kirjutada nii:

lüliti (vastus) {
  juhtum. edu (las andmed):
    // tehke midagi (valikulise) andmetega
  juhtum. rike (lase viga):
    // teha midagi (valikulise) veaga
}

Pange tähele, kuidas andmete ja vea parameetrid on üksteist välistavad.

Dartis ei saa me lisaväärtusi seostada enumidega ja ülaltoodud koodi võidakse rakendada järgmiselt:

klass NetworkResponse {
  NetworkResponse ({this.data, this.error})
  // väide andmete ja vigade vastastikku välistamiseks
  : kinnitama (andmed! = null && viga == null || andmed == null && viga! = null);
  lõplikud Uint8Listi andmed;
  lõplik stringi viga;
}
var vastus = NetworkResponse (andmed: Uint8List (0), viga: null);
if (response.data! = null) {
  // kasuta andmeid
} veel {
  // kasuta viga
}

Paar märkust:

  • Siin kompenseerime väiteid faktiga, et meil pole valikuvõimalusi.
  • Kompilaator ei saa meid aidata kontrollida kõiki võimalikke juhtumeid. Selle põhjuseks on asjaolu, et me ei kasuta vastuse töötlemiseks lülitit.

Kokkuvõtlikult võib öelda, et Swifti enumad on palju võimsamad ja väljendusrikkamad kui Dartis.

Kolmandate osapoolte raamatukogud, näiteks Dart Sealed Unions, pakuvad samasugust funktsionaalsust kui Swift enums pakuvad ja aitavad seda lünka täita.

Loe lisaks: Swift Enums.

Struktuurid

Swiftis saame määratleda struktuurid ja klassid.

Mõlemal konstruktsioonil on palju ühist ja mõned erinevused.

Peamine erinevus on see, et:

Klassid on võrdlustüübid ja struktuurid on väärtustüübid

Dokumentatsiooni tsiteerimine:

Väärtuse tüüp on tüüp, mille väärtus kopeeritakse, kui see on määratud muutujale või konstandile või siis, kui see antakse edasi funktsioonile.
Kõik struktuurid ja loendused on väärtuses Swift väärtused. See tähendab, et kõik teie loodud struktuurid ja loenduse eksemplarid - ja kõik väärtuste tüübid, mis neil omadustena on - kopeeritakse alati, kui need teie koodis ümber käivad.
Erinevalt väärtustüüpidest ei kopeerita viitetüüpe siis, kui nad on määratud muutujale või konstandile või kui nad on antud funktsioonile. Koopia asemel kasutatakse viidet samale olemasolevale eksemplarile.

Mida see tähendab, kaaluge järgmist näidet, kus suuname klassi Isik ümber, et muuta see muutlikuks:

klassi inimene {
  var nimi: Keel
  var vanus: Int
  var kõrgus: kahekordne
  init (nimi: keelpill, vanus: keskmine, kõrgus: kahekordne) {
    ise.nimi = nimi
    self.age = vanus
    ise.kõrgus = kõrgus
  }
}
var a = Isik (nimi: "Andrea", vanus: 34, pikkus: 1,84)
var b = a
b.age = 35
print (a.age) // prindib 35

Kui määratleme inimese ümber struktuuri, on see järgmine:

struct Person {
  var nimi: Keel
  var vanus: Int
  var kõrgus: kahekordne
  init (nimi: keelpill, vanus: keskmine, kõrgus: kahekordne) {
    ise.nimi = nimi
    self.age = vanus
    ise.kõrgus = kõrgus
  }
}
var a = Isik (nimi: "Andrea", vanus: 34, pikkus: 1,84)
var b = a
b.age = 35
print (a.age) // prindib 34

Struktuure on palju rohkem, kui ma siin käsitletud olen.

Struktuuride abil saab Swiftis andmeid ja mudeleid suurepäraselt hallata, mis tagab kindla koodi, milles on vähem vigu.

Parema ülevaate saamiseks lugege: Struktuurid ja klassid Swiftis.

Vigade käsitlemisel

Swift-dokumentide määratluse kasutamine:

Veakäsitlus on teie programmi tõrketingimustele reageerimine ja nendest taastamine.

Nii Dart kui ka Swift kasutavad vigade käsitlemise meetodina proovimist / püüdmist, mõnede erinevustega.

Dart-i puhul võib iga meetod teha erandi mis tahes tüübist.

klassi pangakonto {
  Pangakonto ({this.balance});
  kahekordne tasakaal;
  tühine väljavõtmine (kahekordne summa) {
    if (summa> saldo) {
      viska erand ('ebapiisavad rahalised vahendid');
    }
    tasakaal - = summa;
  }
}

Erandeid saab püüda proovimis- / püügibloki abil:

var konto = pangakonto (saldo: 100);
proovige {
  konto.võta (50); // Okei
  konto.võta (200); // viskab
} saak (e) {
  print (e); // trükitakse “Erand: ebapiisavad rahalised vahendid”
}

Swiftis kuulutame selgesõnaliselt, millal meetod võib erandi teha. Seda tehakse viskamise märksõnaga ja kõik vead peavad vastama tõrkeprotokollile:

enum AccountError: viga {
  juhtum ebapiisavFondid
}
klassi pangakonto {
  var tasakaal: topelt
  init (tasakaal: topelt) {
    enesebilanss = tasakaal
  }
  func väljaviskamine (summa: Double) viskab {
    kui summa> saldo {
      viska kontoError.insufficientFunds
    }
    tasakaal - = summa
  }
}

Vigade käsitlemisel kasutame proovimismeetodit märksõnade võtmise blokis.

var konto = pangakonto (saldo: 100)
tee {
  proovige account.withdraw (summa: 50) // ok
  proovige account.withdraw (summa: 200) // viskab
} saagi AccountError.insufficientFunds {
  print ("Ebapiisavad rahalised vahendid")
}

Pange tähele, kuidas proovimis märksõna on kohustuslik, kui helistate meetoditele, mis võivad visata.

Ja vead ise on tugevalt kirjutatud, nii et meil võib olla mitu saagiplokki, et katta kõiki võimalikke juhtumeid.

proovida, proovida?, proovida!

Swift pakub vähem sõnasõnalisi vigade käsitlemise viise.

Kas me saame proovida? ilma do / catch blokeerimiseta. Ja see põhjustab kõigi erandite eiramist:

var konto = pangakonto (saldo: 100)
proovida? konto.võta välja (summa: 50) // ok
proovida? konto.väljavõtmisega (summa: 200) // ebaõnnestub

Või kui oleme kindlad, et meetod ei viska, võime proovida !:

var konto = pangakonto (saldo: 100)
proovige! konto.võta välja (summa: 50) // ok
proovige! konto.võta välja (summa: 200) // krahh

Ülaltoodud näide põhjustab programmi krahhi. Seega proovige! pole tootekoodis soovitatav ja see sobib paremini testide kirjutamiseks.

Üldiselt on Swifti tõrkekäsitluse otsene olemus API-kujunduses väga kasulik, kuna selle abil on lihtne teada saada, kas meetod võib visata.

Samuti juhib proovikõne kasutamine meetodikõnedes tähelepanu koodile, mis võib visata, sundides meid arvestama veajuhtumitega.

Selles suhtes tundub veahaldus turvalisem ja töökindlam kui Dartis.

Loe rohkem:

  • Noolemängud
  • Swift Vigade käsitlemine

Geneerikud

Tsiteerides Swifti dokumente:

Üldkood võimaldab teil määratleda paindlikke, korduvkasutatavaid funktsioone ja tüüpe, mis võivad töötada mis tahes tüübiga, vastavalt teie määratletud nõuetele. Võite kirjutada koodi, mis väldib dubleerimist ja väljendab oma kavatsust selgelt ja kokkuvõtlikult.

Mõlemad keeled toetavad geneerikat.

Üks geneeriliste ravimite sagedamini kasutatavaid juhtumeid on kogud, näiteks massiivid, komplektid ja kaardid.

Ja me saame neid kasutada oma tüüpide määratlemiseks. Nii määratleksime Swiftis üldise korstnatüübi järgmiselt:

struct Stack  {
  var üksused = [element] ()
  funktsiooni muteerimine (_ üksus: element) {
    items.append (element)
  }
  muteeruv func pop () -> element {
    tagasta artiklid.removeLast ()
  }
}

Samamoodi kirjutaks Dartis:

klassivirn  {
  var üksused =  []
  tühine tõuge (elemendi üksus) {
    üksused.add (üksus)
  }
  tühine pop () -> element {
    tagasta artiklid.removeLast ()
  }
}

Geneerilised tooted on Swiftis väga kasulikud ja võimsad, kus neid saab kasutada tüübipiirangute ja nendega seotud tüüpide määratlemiseks protokollides.

Soovitan lisateabe saamiseks lugeda dokumentatsiooni:

  • Swift Generics
  • Dart Generics

Juurdepääsu kontroll

Tsiteerides Swifti dokumentatsiooni:

Pääsukontroll piirab juurdepääsu teie koodi osadele muude lähtefailide ja moodulite koodide kaudu. See funktsioon võimaldab teil peita oma koodi rakenduse üksikasjad ja määrata eelistatud liidese, mille kaudu sellele koodile juurde pääseb ja seda saab kasutada.

Swiftil on viis juurdepääsu taset: avatud, avalik, sisemine, failide privaatne ja privaatne.

Neid kasutatakse moodulite ja lähtefailidega töötamise kontekstis. Tsiteerimine:

Moodul on üks koodijaotuse ühik - raamistik või rakendus, mis on ehitatud ja tarnitud ühe ühikuna ning mida saab importida mõni muu moodul koos Swifti impordisõnaga.

Avatud ja avaliku juurdepääsu taset saab kasutada koodi moodulitele juurdepääsetavaks muutmiseks.

Privaatset ja faili privaatset juurdepääsu taset saab kasutada koodi muutmiseks juurdepääsematuks väljaspool faili, milles see on määratletud.

Näited:

avalik klass SomePublicClass {}
sisemine klass SomeInternalClass {}
fileprivate klass SomeFilePrivateClass {}
eraklass SomePrivateClass {}

Juurdepääsutasemed on Dartis lihtsamad ja piiratud avaliku ja privaatsega. Tsiteerimine:

Erinevalt Java-st pole Dartil märksõnu avalik, kaitstud ja privaatne. Kui identifikaator algab alakriipsuga _, on see tema kogu jaoks privaatne.

Näited:

klassi HomePage laiendab rakendust StatefulWidget {// avalik
  @ ületamine
  _HomePageState createState () => _HomePageState ();
}
klass _HomePageState laiendab olekut  {...} // privaatset

Ligipääsukontroll oli Darti ja Swifti jaoks mõeldud erinevate eesmärkidega. Ja selle tulemusel on juurdepääsu tase väga erinev.

Loe rohkem:

  • Kiire juurdepääsu kontroll
  • Noolemängude raamatukogud ja nähtavus

Asünkroonne programmeerimine: tulevikud

Asünkroonne programmeerimine on piirkond, kus Dart tõesti paistab.

Selliste kasutusjuhtumitega tegelemisel on vaja mõnda asünkroonset programmeerimist, näiteks:

  • Sisu allalaadimine veebist
  • Rääkimine taustateenusega
  • Sooritage pikka tööoperatsiooni

Nendel juhtudel on kõige parem mitte blokeerida peamist täitmisniiti, mis võib meie programme külmutada.

Darti dokumentatsiooni tsiteerimine:

Asünkroonsed toimingud võimaldavad teie programmil teha muud tööd, oodates toimingu lõppu. Dart kasutab asünkroonsete toimingute tulemuste kajastamiseks tuleviku objekte (futuure). Futuuridega töötamiseks võite kasutada kas asünkrit ja ootamist või Future API-d.

Vaatame näiteks, kuidas saame kasutada asünkroonset programmeerimist:

  • autentida kasutajat serveriga
  • salvestage juurdepääsuluba turvaliseks hoidmiseks
  • hankige kasutaja profiili teavet

Dartis saab seda teha asynciga / oodata koos Futures'iga:

Tulevane  getUserProfile (UserCredentials mandaadid) async {
  final accessToken = ootama networkService.signIn (mandaadid);
  oota SecureStorage.storeToken (accessToken, forUserCredentials: mandaadid);
  tagasi oodake networkService.getProfile (accessToken);
}

Swiftis asünkri / ootamise tugi puudub ja saame seda teha ainult sulgemisega (lõpuleviimise plokid):

func getUserProfile (mandaadid: UserCredentials, täitmine: (_ tulemus: UserProfile) -> Void) {
  networkService.signIn (mandaadid) {accessToken in
    SecureStorage.storeToken (accessToken) {
      networkService.getProfile (accessToken, lõpuleviimine: lõpuleviimine)
    }
  }
}

See viib pesastatud lõpuleviimisplokkide tõttu “surmapüramiidini”. Ja vigade käsitlemine muutub selle stsenaariumi korral väga keeruliseks.

Dart-is saab ülaltoodud koodi vigade käsitlemine lihtsalt lisada proovide / saagi ploki koodi ümber meetodile getUserProfile.

Viiteks on ettepanek lisada asynk / oodata Swifti tulevikus. See on üksikasjalikult dokumenteeritud siin:

  • Async / Oota Swifti ettepanekut

Kuni selle rakendamiseni saavad arendajad kasutada kolmanda osapoole raamatukogusid, näiteks seda Google'i lubaduste teeki.

Darti kohta leiate suurepärase dokumentatsiooni siit:

  • Dart asünkroonne programmeerimine: tulevikud

Asünkroonne programmeerimine: ojad

Vooge rakendatakse Darti tuumaraamatukogude osana, kuid mitte Swiftis.

Darti dokumentatsiooni tsiteerimine:

Voog on asünkroonsete sündmuste jada.

Vood on reaktiivsete rakenduste aluseks, kus neil on oluline roll riigi juhtimisel.

Näiteks ojad on suurepärane valik sisu otsimiseks, kus iga kord, kui kasutaja otsinguväljal teksti värskendab, väljastatakse uus tulemuste komplekt.

Vooge ei sisaldu Swifti tuumakogudes. Kolmandate osapoolte teegid, näiteks RxSwift, pakuvad voogesituste tuge ja palju muud.

Vood on lai teema, mida siin ei arutata.

Loe lisaks: Dart asünkroonne programmeerimine: ojad

Mäluhaldus

Dart haldab mälu täiustatud prügikoristusskeemi abil.

Swift haldab mälu automaatse referentsloenduse (ARC) abil.

See tagab suurepärase jõudluse, kuna mälu vabastatakse kohe, kui seda enam ei kasutata.

Kuid see viib koormuse osaliselt kompilaatorilt arendajale.

Swiftis peame mõtlema objektide elutsüklile ja omandile ning kasutama tsüklite säilimise vältimiseks õigesti sobivaid märksõnu (nõrk, tugev, teadmata).

Loe lisaks: Automaatne viidete automaatne loendamine.

Kompileerimine ja täitmine

Esiteks oluline erinevus vahetult-ajaliselt (JIT) ja enne tähtaega (AOT) koostajate vahel:

JIT koostajad

JIT-kompilaator töötab programmi täitmise ajal, kompileerides lennult.

JIT-i koostajaid kasutatakse tavaliselt dünaamiliste keeltega, kus tüüpe ei ole enne tähtaega fikseeritud. JIT-programme käivitatakse tõlgi või virtuaalmasina (VM) kaudu.

AOT-i koostajad

Programmi loomise ajal enne tööaega töötab AOT-kompilaator.

AOT-kompilaatorit kasutatakse tavaliselt staatiliste keeltega, mis teavad andmete tüüpe. AOT-programmid kompileeritakse natiivse masinkoodina, mida käivitab otse riistvara käitusel.

Tsiteerides seda Wm Leleri suurepärast artiklit:

Kui AOT-i kompilatsioon tehakse arenduse ajal, põhjustab see alati palju aeglasemaid arendustsükleid (aeg programmi muutmise ja programmi käivitamise vahel muudatuse tulemuse nägemiseks). Kuid AOT-i kompilatsiooni tulemuseks on programmid, mida saab paremini ennustada ja käivitada ilma töö ja pausi analüüsimise ja koostamiseta. Ka AOT-i kompileeritud programmid hakkavad kiiremini täitma (kuna need on juba kompileeritud).
JIT-i kompilatsioon pakub vastupidiselt palju kiiremaid arendustsükleid, kuid võib põhjustada aeglasema või jerkier täitmise. Eelkõige on JIT-i kompilaatoritel aeglasemad käivitusajad, sest kui programm käivitatakse, peab JIT-i kompilaator enne koodi käivitamist analüüsima ja kompileerima. Uuringud on näidanud, et paljud inimesed loobuvad rakendusest, kui selle käivitamine võtab rohkem kui paar sekundit.

Staatilise keelena kompileeritakse Swift enne tähtaega.

Noolemängu saab koostada nii AOT kui ka JIT. See pakub koos Flutteriga olulisi eeliseid. Tsiteerin uuesti:

JIT-i kompileerimist kasutatakse arenduse ajal, kasutades eriti kiiret kompilaatorit. Siis, kui rakendus on vabastamiseks valmis, kompileeritakse see AOT. Järelikult suudab Dart arenenud tööriistade ja kompilaatorite abil pakkuda mõlemast maailmast parimat: äärmiselt kiire arengutsükkel ning kiire täitmise ja käivitamise aeg. - Wm Leler

Dartiga saame mõlemast maailmast parima.

Swift kannatab AOT-i koostamise peamise puuduse all. See tähendab, et kompileerimise aeg suureneb koos koodbaasi suurusega.

Keskmise suurusega rakenduse (vahemikus 10–100 000 rida) jaoks võib rakenduse koostamine hõlpsalt võtta minuteid.

Mitte nii Flutteri rakenduste puhul, kus me saame pidevalt sekundaarset kuuma uuesti laadimist, sõltumata koodbaasi suurusest.

Muud omadused pole hõlmatud

Järgmisi funktsioone ei käsitletud, kuna need on Dartis ja Swiftis üsna sarnased:

  • Operaatorid (vt Swift and Dart viidet)
  • Keelpillid (vaata viidet Swift ja Dart)
  • Valikuline aheldamine Swiftis (Dartis tuntud kui liikmetele tingimuslik juurdepääs).

Kooskõla

  • Samaaegset programmeerimist võimaldavad Dartis olevad isolaadid.
  • Swift kasutab Grand Central Dispatchi (GCD) ja saatmisjärjekordi.

Minu lemmik Swifti funktsioonid puuduvad Dartilt

  • Struktuurid
  • Seotud tüüpidega enumad
  • Valikulised

Minu lemmik noolemäng on Swiftilt puudu

  • Just-in-time koostaja
  • Tulevikud ootamisega / asünkriga (vt async / oodake Chris Lattneri ettepanekut)
  • Vood saagise / asünkriga * (RxSwift pakub reaktiivsete rakenduste jaoks voogude superkomplekti)

Järeldus

Nii Dart kui ka Swift on suurepärased keeled, sobivad hästi kaasaegsete mobiilirakenduste loomiseks ja kaugemalegi.

Kumbki keel pole parem, kuna neil mõlemal on oma unikaalsed tugevad küljed.

Mobiilirakenduste arendamist ja kahe keele abivahendeid vaadates tunnen, et Dartil on käes. Selle põhjuseks on JIT-i kompilaator, mis on Flutteri riikliku kuuma laadimise aluseks.

Kuumlaadimine annab rakenduste ehitamisel tohutu tootlikkuse kasvu, kuna see kiirendab arendustsüklit sekunditest või minutitest vähem kui sekundini.

Arendaja aeg on vähem ressurss kui arvutustehnika aeg.

Nii et arendaja aja jaoks optimeerimine on väga nutikas samm.

Teisest küljest tunnen, et Swiftil on väga tugev tüübisüsteem. Tüübi ohutus on sisse arvestatud kõigisse keelefunktsioonidesse ja viib loomulikult tugevamate programmide juurde.

Kui oleme isiklikud eelistused kõrvale jätnud, on programmeerimiskeeled lihtsalt tööriistad. Ja meie kui arendajate ülesanne on valida selle töö jaoks kõige sobivam tööriist.

Igal juhul võime loota, et mõlemad keeled laenavad arenedes üksteiselt parimaid ideid.

Viited ja krediidid

Nii Dartil kui ka Swiftil on ulatuslik funktsioonide komplekt ja neid pole siin täielikult käsitletud.

Ma koostasin selle artikli laenuteabe ametlikust Swifti ja viskamise dokumentatsioonist, mille leiate siit:

  • Kiire programmeerimiskeel
  • Darti keele ringkäik

Lisaks on JITi ja AOTi koostajaid käsitlev jaotis suuresti inspireeritud sellest suurepärasest Wm Leleri artiklist:

  • Miks laperdus kasutab viskamist

Kas ma olen millestki ilma jäänud? Andke mulle kommentaarides teada.

Head kodeerimist!

UPDATE: Minu Flutter & Firebase Udemy kursus on nüüd varase juurdepääsu jaoks saadaval. Kasutage registreerumiseks seda linki (kaasa arvatud sooduskood):

  • Flutter & Firebase: looge täielik rakendus iOS-i ja Androidi jaoks

Rohkem artikleid ja videoõpetusi leiate jaotisest Kodeerimine koos laperdamisega.

Olen @ biz84 Twitteris. Võite näha ka minu GitHubi lehte.