Shanraq.org Shanraq.org
Go-дағы жиым мен тілім (slice): өсетін тізім, append, len және cap
IT

Go тілі: нөлден өз блогыңызға дейін 8-сабақ (барлығы 50)

Go-дағы жиым мен тілім (slice): өсетін тізім, append, len және cap

Go курсының сегізінші сабағы. Тілім неден жасалған — жиым, әрі тілімнің өзі: []string, append және нәтижені неге кері меншіктеу керек. Меншіктегенде жиым мен тілім несімен ерекшеленеді, ұзындық пен сыйымдылық несімен, әрі басты тұзақ: кесілген бөлік сол бір жадты пайдаланады.

Не үшін керек

Осы уақытқа дейін бір ат бір мәнді сақтап келді. Ал блогта мақала біреу емес, тегі бірнешеу, пікірі де солай. Тізім керек, ал Go-да ол тілім деп аталады. Ағылшынша slice — «тілім» деген сөз: нанның бір тілімі сияқты, бүтіннен кесіп алынған бөлік. Құжаттамада да, қате хабарламаларында да ағылшын сөзі тұрады, сондықтан екеуін де біліп қойған жөн.

Сонымен бірге for уәдесінің екінші жартысын береді: жол үшін алған range енді тізімді аралайды.

Бірден тұтас

Жаңа қалта, go mod init sabaq07, main.go:

package main

import "fmt"

func main() {
	var titles []string

	titles = append(titles, "Шаңырақ")
	titles = append(titles, "Go тілі")
	titles = append(titles, "Дала")

	fmt.Println("мақала:", len(titles), "· орын:", cap(titles))

	for i, t := range titles {
		fmt.Println(i+1, t)
	}

	fmt.Println("алғашқы екеуі:", titles[:2])
	fmt.Println("соңғысы:", titles[len(titles)-1])
}

Іске қоспас бұрын — төменге қарамай, оның не басып шығаратынын дауыстап айтыңыз. Содан кейін жіберіп, салыстырыңыз: айырма шыққан жер — тілді әлі білмейтін тұсыңыз.

go run . мынаны басып шығарады:

мақала: 3 · орын: 4
1 Шаңырақ
2 Go тілі
3 Дала
алғашқы екеуі: [Шаңырақ Go тілі]
соңғысы: Дала

Байқаңыз: мақала үшеу, ал орын төртеу. Төрттікті есте сақтамаңыз: қанша қор алуды жүзеге асыру шешеді, әрі Go-ның басқа нұсқасында сан өзгеше болуы мүмкін. Тексеру керегі — len, ал cap — тек бақылайтын нәрсе.

Талдау

Алдымен жиым: тілім неден жасалған

«Жиым» деген сөз жаңа ғана айтылды — оны аяғына дейін айтып алайық, өйткені онсыз тілімді түсіндіру мүмкін емес.

Go-дағы жиым — ұзындығы бірде-бір рет белгіленген және типтің өзіне кіретін тізім. [3]string пен [4]stringәртүрлі тип, біреуін екіншісіне меншіктеуге болмайды. Сондықтан кәдімгі кодта жиымды жазбайды деуге болады: элемент саны алдын ала белгілі болатын жағдай сирек.

Бір айырмашылықты міндетті түрде білу керек, өйткені қалғанының бәрі содан шығады. Жиым меншіктегенде көшіріледі, тілім — жоқ:

titles := [3]string{"Шаңырақ", "Go тілі", "Дала"}
copyOf := titles
copyOf[0] = "Таулар"
fmt.Println("жиым: ", titles[0], "·", copyOf[0])

list := []string{"Шаңырақ", "Go тілі", "Дала"}
same := list
same[0] = "Таулар"
fmt.Println("тілім:", list[0], "·", same[0])
жиым:  Шаңырақ · Таулар
тілім: Таулар · Таулар

Жиымды меншіктедік — екінші, тәуелсіз үш жол пайда болды, біріншісін өзгерту оған тимейді. Тілімді меншіктедік — екі ат та бір жиымға қарайды, сондықтан бір ат арқылы енгізілген түзету екіншісі арқылы да көрінеді.

Тілім деген шын мәнінде осы: үш сан — жиымның мекенжайы, ұзындық және сыйымдылық. Дерек жиымда жатыр, тілім оған қалай жетуді ғана айтады. append-тің кейде «көшіп кететіні» де содан: жиымдағы орын бітті, үлкенірек жиым ашылады.

Элементтерді қолмен санаудың қажеті жоқ: [...]string{"Шаңырақ", "Go тілі", "Дала"} — бұл да жиым, ұзындығын компилятор санайды.

Жиым қайда кездеседі: ұзындық мағынаның бөлігі болатын жерде. SHA-256 хеші — [32]byte, оның басқа ұзындығы болуы мүмкін емес. Мұндай жерде жиым өлшемді типтің өзінде айтып тұр.

[]string — жолдар тілімі

Түрдің алдындағы тік жақша — сол тілім. Іші бос: ұзындық алдын ала берілмейді, тізім қажетінше өседі.

var titles []string

Мұндай тілім бос, және бұл заңды күй: len нөл, cap нөл, ал мәннің өзі — nil. Оған бірден қоса беруге болады, ешқандай дайындық керек емес.

append қосады — және жаңа тілім қайтарады

titles = append(titles, "Дала")

Сол жақта да, оң жақта да бір ат тұр, бұл қате емес. append ескі тілімді өзгертпейді, ол жаңасын қайтарады. Орын жетсе, элементті сол массивке жазып, жаңа ұзындықты тілім береді; жетпесе — үлкенірек массив ашады, сонда тілім басқа мекенжайда болады. Кері меншіктеуді ұмытсаңыз, қосқаныңыз жоғалады, ал бағдарлама тіпті шағымданбайды.

Елестетіп көріңіз. Көшу. Тағы бір затты қойып жіберуді сұрайсыз, ал сізге: «сыйды, бірақ көшуге тура келді, міне жаңа мекенжай» дейді. Мекенжайды жазып алмасаңыз, ескісіне барып, ондағы бәрі баяғыша тұрғанына таңғаласыз.

Бұл — көпшілік кемінде бір рет жіберетін қате. Одан кейін қол өзі x = append(x, …) деп жазатын болады.

Ұзындық пен сыйымдылық

len — қанша элемент жатыр. cap — көшу керек болғанға дейін қаншасы сыяды.

Мысалда олар үшеу және төртеу: Go әр қосқан сайын тізімді көшірмес үшін орынды қорымен алған.

Елестетіп көріңіз. Сөредегі қорап. Ұзындық — қазір ішінде қанша кітап бар. Сыйымдылық — үлкенірек қорап алып, бәрін соған ауыстырғанға дейін қаншасы сыяды.

Сыйымдылықты білген пайдалы, бірақ оны қолмен басқарудың қажеті көбіне жоқ: Go оны өзі, қорымен ұлғайтады — шағын тілімді екі есе, әрі қарай сабырлырақ. Жаңа сыйымдылық дәл қанша болатынына тіл кепілдік бермейді, бағдарламада оған сүйенуге болмайды. Маңыздысы басқа: мың рет қосу мың көшу емес, он шақты көшу тұрады.

Индекс және шекара

Бірінші элемент — titles[0], соңғысы — titles[len(titles)-1]. Санақ нөлден.

Шекарадан шығу кешірілмейді: элемент үшеу болғанда titles[5] деу бағдарламаны index out of range хабарымен тоқтатады. Бұл үнсіз қоқыс қайтарғаннан жақсы — қате туралы бір аптадан кейін оқырманнан емес, дәл сол секундта білесіз.

Тілімнен тілім кесу

titles[:2]    // алғашқы екеуі
titles[1:]    // екіншісінен соңына дейін
titles[1:3]   // екіншісінен үшіншісіне дейін

Бірінші сан — қайдан, екіншісі — қайсысына дейін, оны қоспай. Түсіп қалғаны «басынан» немесе «соңына дейін» дегенді білдіреді.

Тұзақ: кесілген тілім — көшірме емес

Осы бөлім содан да керек:

two := titles[:2]
two[0] = "ӨЗГЕРДІ"
fmt.Println(titles[0])   // ӨЗГЕРДІ

Біз two-ні түзеттік, ал titles өзгерді. Тілімнен кесілген тілім — бөлек тізім емес, сол жадқа ашылған терезе.

Елестетіп көріңіз. Құжаттың көшірмесі емес, сол қойманың өзіне ашылған терезе. Терезеден сөренің бір бөлігі көрінеді, ал сол терезе арқылы бірдеңені жылжытсаңыз, ол қойманың өзінде жылжыған.

Шын көшірме керек болса, оны айқын жасаңыз:

two := make([]string, 2)
copy(two, titles[:2])

Әзірге бір нәрсені есте ұстаңыз: тілімнен кесілген тілім онымен жадты бөліседі. Көпшілікке бұл кедергі емес, бірақ бір күні «неге өзгергені түсініксіз» болғанда — осы абзацты еске түсіріңіз.

Тізім бойынша range

for i, t := range titles {

Жолдағыдай, бірақ қарапайымырақ: i — нөлден басталатын реттік нөмір, ешқандай байтсыз, t — элементтің өзі. Нөмір керек болмаса, оның орнына астыңғы сызық қойылады: for _, t := range titles.

Сабақ картасы

Сабақ картасы: ұзындығы үш, сыйымдылығы төрт

Өз сөзіңізбен айтыңыз

Қарамай, дауыстап немесе қағазға жазып жауап беріңіз. Жауаптары — сабақтың соңында.

  1. append неге жай ғана append(x, v) емес, x = append(x, v) болып жазылады?
  2. Ұзындықтың сыйымдылықтан айырмашылығы неде және екіншісі не үшін керек?
  3. Сіз part := titles[:2] деп кесіп алып, part[0]-ді түзеттіңіз. titles[0] не болды және неге?

Тапсырма

Міндетті. longer(titles []string, n int) []string функциясын жазыңыз — тек n әріптен көп тақырыптарды қайтарады. Байтты емес, әріпті санаңыз — өткен сабақтағыдай. Оны "Дала", "Шаңырақ", "Go", "Көш" тізімі үшін n = 3 болғанда шақырып, нәтижесін басып шығарыңыз.

Қалауыңызша.

  • total(nums []int) int функциясы — тізімдегі сандардың бәрін қосады.
  • Циклмен тізімге он тақырып қосып, әрқайсысынан кейін len мен cap басып шығарыңыз. Сыйымдылық қай қадамда өзгереді?
  • make пен copy арқылы алғашқы екі тақырыптың шын көшірмесін жасаңыз, көшірмені түзетіп, түпнұсқаның бүтін екеніне көз жеткізіңіз.

Блогта қайда тұрады

Басты беттегі мақалалар тізімі, тақырып астындағы тегтер, мәтін астындағы пікірлер, іздеу нәтижелері — бәрі тілім. Шаблон сабағында осындай тізімді HTML-ге бересіз де, ол карточкаларға жайылады; дерекқор сабағында оны бір сұраумен сол жерден аласыз.

Жауаптар

Жауаптарды көрсету
  1. Себебі append ескісін өзгертпей, жаңа тілім қайтарады. Орын жетпегенде ол деректерді көшіріп жібереді де, мекенжай өзгереді; меншіктемесеңіз, сізде ескі мән қалады, ал қосқаныңыз жоғалады. Компилятор бұл туралы ескертпейді: ол нәтижесі алынбаған функция шақыруын ғана көреді.
  2. Ұзындық — қазір қанша элемент бар, сыйымдылық — көшкенге дейін қаншасы сыяды. Екіншісі әр қосқан сайын тізім көшіп жүрмес үшін керек: Go орынды қорымен алып, оны өзі ұлғайтады, сондықтан мың рет қосу шамамен он шақты көшумен бітеді. Сыйымдылық дәл қанша өсетініне тіл кепілдік бермейді.
  3. titles[0] да «ӨЗГЕРДІ» болды. Тілімнен кесілген тілім деректерді көшірмейді, сол негізгі массивтің жадын ортақ пайдаланады, сондықтан біреуі арқылы жасалған түзету екіншісінен көрінеді. Көшірме make пен copy арқылы айқын жасалады.

Дереккөздер

Мәтінде қате не теру қатесі кездессе, бізге айтыңыз

Тапсырманы тексеру

Алдымен VS Code-та шешіп, іске қосыңыз — редактор қатені сол жерде көрсетеді. Дайын шешімді осында қойыңыз. Тексеретін — модель: ол қатені атап көрсетеді, бірақ дайын жауапты бермейді.

Тексеру үшін кіру керек. Кіру

Пікірлер (0)

Әзірге пікір жоқ. Бірінші болыңыз.