Съдържание на курса
Урок 2 — Променливи, функции и типове
От Dorian Chávez · основател на Hábil и архитект на интеграции ·
Продължителност: 90 минути или две сесии по 45.
Като приключиш, ще можеш:
- Да обясниш какво прави компилаторът на Go с твоя текстов файл.
- Да декларираш променливи и да знаеш кога да използваш
:=и кога=. - Да назовеш четирите основни типа и да кажеш защо Go не ти позволява да ги смесваш.
- Да пишеш функции, които получават и връщат стойности.
- Да разбереш защо една функция на Go може да върне две неща едновременно.
- Да четеш съобщенията за грешки на компилатора и да знаеш какво иска от теб.
- Да напишеш, компилираш и изпълниш пълна програма сам.
Защо е важно
revisor — програмата, която ще изграждаш през целия курс — има нужда още от първия си ред от
три неща: данни (името на една услуга, нейния порт, колко време ѝ е отнело да отговори), логика, която
да реши нещо с тези данни (бърза ли е, или бавна?), и начин да предупреди, когато нещо се е объркало (услугата
не е отговорила?). Точно това, в този ред, преподава този урок: променливи, за да
пазиш данни, функции за логиката и шаблона с две върнати стойности за грешките.
Не е случайно, че Go е компилиран и със статични типове: и двете решения съществуват, за да може
компютърът да хване грешките ти преди програмата да се изпълни, вместо да ги открие потребител в
продукция. Интерпретираният език те оставя да напишеш puerto = "muchos" и гърми едва когато този ред се
изпълни — което може да е десет минути по-късно или никога, ако този път в кода почти не се използва. Go отказва
да създаде изпълнимия файл. Тази разлика е дълбоката причина за почти всичко, което ще видиш в този урок:
защо компилаторът е строг, защо съществува „нулевата стойност“ и защо функция, която може да се провали,
трябва да го каже в сигнатурата си, а не като изненада.
В края на урока ще напишеш първата истинска стъпка на revisor (проектно упражнение): функция,
която получава името на една услуга, нейния порт и времето ѝ за отговор и връща класифициран ред от
отчета. Все още без structs, без конкурентност и без HTTP — те идват по-късно — но вече е код, който
прилича на крайната програма.
Понятията
2.1 Какво прави компилаторът
Пишеш текстов файл. Сам по себе си този файл не прави нищо: той е текст. За да може компютърът да го изпълни, нещо трябва да го преведе в инструкциите, които процесорът разбира.
Има два начина да се направи този превод:
| Как работи | Езици | |
|---|---|---|
| Интерпретиран | Една програма чете текста ти ред по ред и прави това, което пише, всеки път, когато го изпълниш | Python, JavaScript, PHP |
| Компилиран | Една програма превежда целия ти текст само веднъж и записва резултата в изпълним файл | Go, C, C++, Rust |
Go е компилиран и това има три последици, които ще забележиш още от днес:
- Има стъпка преди изпълнението: компилирането. Ако си сбъркал името на някоя променлива, разбираш там — преди програмата да се изпълни. При интерпретиран език щеше да разбереш, когато изпълнението стигне до този ред, което може да е десет минути по-късно или никога.
- Резултатът е файл, който работи сам. Не е нужно другият компютър да има инсталиран Go.
- Бърз е при изпълнение, защото преводът вече е направен.
2.2 Първата ти програма, ред по ред
Ще напишем, компилираме и изпълним пълна програма. Всички програми в този курс са пълни и изпълними: никакви фрагменти, които не могат да се пуснат.
Подготви папката:
mkdir -p ~/w/curso-go/cap01 && cd ~/w/curso-go/cap01
go mod init cap01
Фиг. 2.1 | Програма, която отпечатва съобщение.
1 // fig02_01.go
2 // Imprime un mensaje en la pantalla.
3 package main
4
5 import "fmt"
6
7 func main() {
8 fmt.Println("Bienvenido a Go!")
9 }
Компилирай я и я изпълни:
$ go run fig02_01.go
Bienvenido a Go!
А сега всеки ред, защото всеки има причина:
Редове 1-2. Коментари. Започват с // и компилаторът ги пренебрегва напълно. Те са за онзи, който
чете кода — включително ти след три седмици.
Ред 3: package main. Всеки файл на Go принадлежи на пакет, който е група от код.
Пакетът main е специален: той е единственият, който създава изпълнима програма. Ако напишеш
package utilidades, ще имаш библиотека, която други програми могат да използват, но която не може да
се изпълни сама.
Ред 5: import "fmt". Казва на компилатора, че ще използваш код от пакета fmt (от format),
който идва с Go и съдържа функциите за отпечатване и форматиране на текст. Go не зарежда нищо по
подразбиране: всичко, което използваш, го поискваш.
Ред 7: func main() {. Декларира функцията main, която е мястото, откъдето започва изпълнението на
програмата. Когато изпълниш програма на Go, системата търси точно тази функция. Ако я наречеш
principal или inicio, програмата няма да тръгне.
Ред 8: fmt.Println("Bienvenido a Go!"). Извиква функцията Println, която се намира в пакета
fmt. Точката се чете като „от“: „функцията Println от fmt“. Println отпечатва това, което ѝ дадеш, и
минава на следващия ред (print line).
Ред 9: }. Затваря тялото на функцията. В Go фигурните скоби ограждат блокове, също както в C,
C++, Java или JavaScript.
2.2.1 Разликата между go run и go build
Фиг. 2.2 | Двата начина да изпълниш програмата си.
$ go run fig02_01.go # compila en memoria, ejecuta, y no deja archivo
Bienvenido a Go!
$ go build fig02_01.go # compila y GUARDA el ejecutable
$ ls -la
-rwxr-xr-x 1 usuario usuario 1841624 fig02_01 ← el programa
-rw-r--r-- 1 usuario usuario 104 fig02_01.go ← tu texto
$ ./fig02_01 # y se ejecuta directo
Bienvenido a Go!
Обърни внимание на размерите: текстът ти е 104 байта; компилираната програма — 1.8 мегабайта. Разликата е, че изпълнимият файл носи в себе си всичко, от което има нужда, за да работи.
2.3 Променливи
Променливата е място в паметта с име, в което пазиш данни, които програмата ти ще използва.
Фиг. 2.3 | Деклариране на променливи и отпечатването им.
1 // fig02_03.go
2 // Declara variables de distintos tipos y las imprime.
3 package main
4
5 import "fmt"
6
7 func main() {
8 nombre := "catalogo" // texto
9 puerto := 443 // número entero
10 tiempo := 0.142 // número con decimales
11 seguro := true // verdadero o falso
12
13 fmt.Println("servicio:", nombre)
14 fmt.Println("puerto:", puerto)
15 fmt.Println("tiempo de respuesta:", tiempo)
16 fmt.Println("usa HTTPS:", seguro)
17 }
$ go run fig02_03.go
servicio: catalogo
puerto: 443
tiempo de respuesta: 0.142
usa HTTPS: true
Операторът := се чете „декларирай нова променлива и запиши в нея това“. Go гледа стойността отдясно
и сам извежда типа: "catalogo" е в кавички, значи е текст; 443 няма кавички и няма
точка, значи е цяло число.
2.3.1 := срещу =
Щом променливата вече съществува, за да ѝ смениш стойността, използваш = без двоеточието:
Фиг. 2.4 | Създаване и промяна на променлива.
1 // fig02_04.go
2 package main
3
4 import "fmt"
5
6 func main() {
7 puerto := 443 // la CREA con valor 443
8 fmt.Println(puerto)
9
10 puerto = 8080 // le CAMBIA el valor
11 fmt.Println(puerto)
12 }
$ go run fig02_04.go
443
8080
2.3.2 Go отказва да компилира, ако не използваш някоя променлива
Фиг. 2.5 | Програма, която не се компилира, нарочно.
1 // fig02_05.go — este programa NO compila
2 package main
3
4 import "fmt"
5
6 func main() {
7 nombre := "catalogo"
8 edad := 30 // se declara y nunca se usa
9 fmt.Println(nombre)
10 }
$ go run fig02_05.go
# command-line-arguments
./fig02_05.go:8:5: declared and not used: edad
Go не го позволява. Това не е предупреждение, което можеш да пренебрегнеш: това е грешка, която спира компилацията.
Защо толкова строго? Защото неизползваната променлива почти винаги означава едно от две неща: сбъркал си името на друг ред или е останал боклук от код, който си изтрил наполовина. И двете са проблеми. Go предпочита да те подразни днес, отколкото да остави мъртъв код да се трупа завинаги.
2.4 Основните типове
Типът е отговорът на въпроса „какъв вид данни е това?“. Четирите, които ще използваш през цялото време:
| Тип | Какво пази | Примери | Нулева стойност |
|---|---|---|---|
string |
текст | "hola", "https://catalogo.example.com" |
"" (празен) |
int |
цели числа | 42, -7, 0 |
0 |
float64 |
числа с десетична част | 3.14, 0.142 |
0 |
bool |
истина или лъжа | true, false |
false |
2.4.1 Go не смесва типове
Фиг. 2.6 | Още една програма, която не се компилира, нарочно.
1 // fig02_06.go — este programa NO compila
2 package main
3
4 import "fmt"
5
6 func main() {
7 puerto := 443
8 puerto = "muchos" // intenta guardar texto en un entero
9 fmt.Println(puerto)
10 }
$ go run fig02_06.go
# command-line-arguments
./fig02_06.go:8:14: cannot use "muchos" (untyped string constant) as int value in assignment
В Python това би работило без оплакване. В Go не се компилира и това е огромно предимство:
2.4.2 Нулевата стойност: в Go никога няма боклук
Фиг. 2.7 | Променливи, декларирани без стойност.
1 // fig02_07.go
2 // Muestra el valor cero de cada tipo basico.
3 package main
4
5 import "fmt"
6
7 func main() {
8 var texto string
9 var entero int
10 var decimal float64
11 var logico bool
12
13 fmt.Printf("string: %q\n", texto)
14 fmt.Printf("int: %d\n", entero)
15 fmt.Printf("float64: %v\n", decimal)
16 fmt.Printf("bool: %t\n", logico)
17 }
$ go run fig02_07.go
string: ""
int: 0
float64: 0
bool: false
Формата var nombre tipo декларира променлива, без да ѝ дава стойност. В други езици това би оставило
„боклук“ — каквото е имало в тази памет — или специално състояние „недефинирано“. В Go тя винаги получава
валидна стойност, наречена нулева стойност.
И тук се появява Printf, която е различна от Println: получава шаблон с празни места и ги
попълва едно по едно. Всяко празно място започва с %:
| За какво | |
|---|---|
%d |
цяло число (decimal) |
%s |
текст (string) |
%q |
текст с кавички (quoted) — полезно, за да видиш дали нещо е празно |
%t |
bool (true/false) |
%v |
каквото и да е, в естествения му формат (value) |
\n |
нов ред (Printf не минава сама на нов ред, Println — да) |
2.5 Функции
Функцията е именуван блок от код, на който можеш да подадеш данни и който може да ти върне
резултат. Вече използва две: fmt.Println и fmt.Printf.
Фиг. 2.8 | Дефиниране и извикване на функции.
1 // fig02_08.go
2 // Define funciones que reciben y devuelven valores.
3 package main
4
5 import "fmt"
6
7 // sumar recibe dos enteros y devuelve su suma.
8 func sumar(a int, b int) int {
9 return a + b
10 }
11
12 // etiqueta arma un texto descriptivo del servicio.
13 func etiqueta(nombre string, puerto int) string {
14 return fmt.Sprintf("%s:%d", nombre, puerto)
15 }
16
17 // esSeguro dice si el puerto corresponde a HTTPS.
18 func esSeguro(puerto int) bool {
19 return puerto == 443
20 }
21
22 func main() {
23 fmt.Println("2 + 3 =", sumar(2, 3))
24 fmt.Println(etiqueta("catalogo", 443))
25 fmt.Println("catalogo es seguro:", esSeguro(443))
26 fmt.Println("local es seguro:", esSeguro(8080))
27 }
$ go run fig02_08.go
2 + 3 = 5
catalogo:443
catalogo es seguro: true
local es seguro: false
Анатомия на ред 8, където е всичко:
func sumar (a int, b int) int {
│ │ │ │
│ │ │ └── lo que DEVUELVE
│ │ └── lo que RECIBE (los parámetros), con su tipo
│ └── el nombre
└── palabra clave: «voy a definir una función»
Ред 14: fmt.Sprintf. Като Printf е, но вместо да отпечата, връща сглобения текст.
S е от string. Използва се изключително много.
Ред 19: puerto == 443. Двойното равно сравнява и дава true или false. Единичното равно =
присвоява. Объркването им е класика (виж „Какво се прави погрешно“ по-долу).
2.6 Връщане на две стойности: подписът на Go
Това е най-характерното за Go и ще го пишеш хиляди пъти в кариерата си. Внимавай.
Помисли за функция, която дели две числа. Какво прави, ако делителят е нула? Не може да върне число, защото резултатът не съществува.
Други езици използват изключения: функцията „хвърля“ грешка и някой по-нагоре я „хваща“ с
try / catch. Проблемът е, че не е очевидно кой я хваща, нито къде, и е изключително лесно никой да не го
направи и програмата да умре.
Go прави нещо друго: връща две стойности. Резултата и грешка.
Фиг. 2.9 | Функция, която връща резултат и евентуална грешка.
1 // fig02_09.go
2 // Devuelve dos valores: el resultado y un posible error.
3 package main
4
5 import (
6 "errors"
7 "fmt"
8 )
9
10 // dividir devuelve el cociente y un error si el divisor es cero.
11 func dividir(a int, b int) (int, error) {
12 if b == 0 {
13 return 0, errors.New("division entre cero")
14 }
15 return a / b, nil
16 }
17
18 func main() {
19 // caso que funciona
20 resultado, err := dividir(10, 2)
21 if err != nil {
22 fmt.Println("error:", err)
23 } else {
24 fmt.Println("10 / 2 =", resultado)
25 }
26
27 // caso que falla
28 resultado, err = dividir(10, 0)
29 if err != nil {
30 fmt.Println("error:", err)
31 } else {
32 fmt.Println("10 / 0 =", resultado)
33 }
34 }
$ go run fig02_09.go
10 / 2 = 5
error: division entre cero
Ред 11: (int, error). Скобите с два типа означават „тази функция връща две
неща“: цяло число и грешка.
Ред 13: return 0, errors.New(...). Когато има проблем, връща някаква произволна стойност (тук 0,
която няма да се използва) и грешка, която описва какво се е случило.
Ред 15: return a / b, nil. Когато всичко е наред, връща резултата и nil.
🔑 nil означава „нищо“, „празно“, „няма“. Тогава въпросът if err != nil се чете:
„грешката различна ли е от нищо?“, или на нормален език: „имаше ли грешка?“
Редове 20-21: шаблонът, който определя Go.
resultado, err := dividir(10, 2)
if err != nil {
// algo salió mal: aquí se atiende
}
// si llegaste aquí, todo bien
Този шаблон if err != nil е най-често писаният ред в цялата история на Go. Появява се навсякъде
и има хора, които го критикуват като повтарящ се.
2.7 Да съберем всичко заедно
Фиг. 2.10 | Пълна програма, която използва всичко от урока.
1 // fig02_10.go
2 // Clasifica servicios por su tiempo de respuesta.
3 package main
4
5 import "fmt"
6
7 // clasificar traduce milisegundos a una etiqueta legible.
8 func clasificar(ms int) string {
9 if ms < 0 {
10 return "sin medir"
11 } else if ms < 500 {
12 return "rapido"
13 } else if ms < 3000 {
14 return "lento"
15 }
16 return "muy lento"
17 }
18
19 // reporte arma una linea del informe.
20 func reporte(nombre string, puerto int, ms int) string {
21 return fmt.Sprintf("%-10s :%-5d %6dms %s",
22 nombre, puerto, ms, clasificar(ms))
23 }
24
25 func main() {
26 fmt.Println("SERVICIO PUERTO TIEMPO ESTADO")
27 fmt.Println("-------------------------------------")
28 fmt.Println(reporte("catalogo", 443, 142))
29 fmt.Println(reporte("pagos", 443, 87))
30 fmt.Println(reporte("inventario", 443, 2310))
31 fmt.Println(reporte("reportes", 3001, 4500))
32 fmt.Println(reporte("viejo", 8080, -1))
33 }
$ go run fig02_10.go
SERVICIO PUERTO TIEMPO ESTADO
-------------------------------------
catalogo :443 142ms rapido
pagos :443 87ms rapido
inventario :443 2310ms lento
reportes :3001 4500ms muy lento
viejo :8080 -1ms sin medir
Тази програма вече е пряк предшественик на revisor: clasificar и reporte са, в миниатюра, това,
което в урок 3 ще се превърне в метод на struct Servicio, а в урок 6 ще се изпълнява за
няколко услуги едновременно.
Ред 21: %-10s и %-5d. Числото казва колко знака ширина да се запазят, а знакът минус
означава подравнено вляво. Така колоните остават прави. Без това таблицата би излязла крива.
Грешката, която ще видиш
Почти всички съобщения за грешка на Go имат една и съща форма:
<archivo>:<línea>:<columna>: <qué esperaba el compilador y qué encontró>
Да се научиш да четеш този ред е половината работа. Два примера, които вече видя в този урок:
./fig02_05.go:8:5: declared and not used: edad
Чете се: „във файла fig02_05.go, ред 8, колона 5, си декларирал edad и никога не си я използвал“.
Поправката е лесна: или използваш променливата, или я изтриваш, или — ако наистина ти трябва декларирана, но още
не я използваш — я заменяш с празния идентификатор _.
./fig02_06.go:8:14: cannot use "muchos" (untyped string constant) as int value in assignment
Чете се: „на ред 8, колона 12, опита да използваш текста "muchos" там, където се очакваше int, и не
ти позволявам“. Поправката обаче не е лесна за отгатване, ако никога не си я виждал: не съществува
автоматично преобразуване между string и int при такова присвояване. Ще трябва да преобразуваш изрично (със
strconv, който ще видим по-нататък) или, по-вероятно, да осъзнаеш, че си объркал типа по грешка.
И трета, най-честата през първата седмица, която се появява, ако използваш отново := върху променлива, която вече
съществува:
./fig02_04.go:10:9: no new variables on left side of :=
Чете се: „от лявата страна на := няма нито една нова променлива“ — всички вече са съществували, така че Go не
знае какво да декларира. Поправката: използвай = вместо :=, когато вече си декларирал променливата по-рано.
Общото правило: компилаторът на Go почти никога не казва „нещо се обърка“ абстрактно. Казва файла, реда, колоната и фраза, която — макар да звучи странно първия път — описва точно проблема. Да я прочетеш цялата, без да се стряскаш, решава повечето случаи, без да се налага да търсиш нещо в интернет.
Какво се прави погрешно
- Писане на
printlnс малка буква вместоPrintln. Go различава главни от малки букви:Printlnиprintlnса различни имена (printlnе вътрешна функция на компилатора, предназначена за отстраняване на грешки в самия Go, а не в твоята програма). Грешката еundefined: fmt.println. - Използване на
import "fmt"без да го използваш, или използване наfmt.Printlnбезimport. Първото дава"fmt" imported and not used; второто —undefined: fmt. И двете са един и същи вид грешка: казал си на компилатора нещо, което не съвпада с онова, което си направил. - Объркване на
=(присвояване) с==(сравнение) вътре вif. В C това би се компилирало и би направило нещо неочаквано (би присвоило стойността и би продължило нататък). В Go това е грешка при компилация —cannot use puerto = 443 (...) as value—, което е добра новина: спира те, преди програмата да направи нещо, което не си поискал. - Забравяне на
\nвPrintf. Програмата се компилира и се изпълнява, но всичко излиза слепено на един ред.Printlnминава на нов ред автоматично;Printf— не. Това е тиха грешка, а не такава, която компилаторът да ти посочи. - Пренебрегване на грешката с
_, ето така:resultado, _ := dividir(10, 0). И това се компилира, и програмата продължава напред сresultado, равно на0, сякаш всичко е наред. Това е най-бързият начин да създадеш грешка, която после е невъзможно да откриеш, защото няма никакво съобщение, нито срив: програмата просто продължава с невярна стойност. Ако някога изхвърлиш грешка с_, нека това бъде съзнателно и коментирано решение, а никога рефлекс, за да спре компилаторът да се оплаква.
Упражнения
Въпроси за преговор
Отговори, без да гледаш отговорите. Те са в края на този раздел.
2.1 Каква е разликата между компилиран и интерпретиран език и кой от двата е Go?
2.2 Защо функцията, от която започва програмата, трябва да се казва точно main?
2.3 Каква е разликата между := и =?
2.4 Каква грешка дава Go, ако декларираш променлива и не я използваш? Защо мислиш, че го прави?
2.5 Какво е нулевата стойност и каква е тя за string, int и bool?
2.6 Какво отпечатва тази програма?
package main
import "fmt"
func main() {
var n int
var s string
fmt.Printf("[%d] [%q]\n", n, s)
}
2.7 Каква е разликата между Println, Printf и Sprintf?
2.8 Какво означава nil и какво пита if err != nil?
2.9 Тази програма има три грешки, които пречат да се компилира. Намери ги, без да я пускаш.
package main
func main() {
nombre := "catalogo"
puerto := 443
puerto := 8080
fmt.Println(nombre)
}
Отговори
2.1 Интерпретираният език се превежда ред по ред при всяко изпълнение; компилираният се превежда изцяло само веднъж и създава изпълним файл. Go е компилиран.
2.2 Защото това е конвенция на езика: при изпълнение на програма Go търси функцията main от
пакета main, за да започне. С друго име не намира откъде да тръгне.
2.3 := декларира нова променлива и ѝ присвоява стойност; = само присвоява на вече съществуваща.
2.4 declared and not used. Прави го, защото неизползваната променлива почти винаги показва грешка —
сбъркано име или остатъци от изтрит код — и Go предпочита да те спре, отколкото да остави мъртъв код.
2.5 Това е стойността, която автоматично получава променлива, декларирана без стойност. string → "",
int → 0, bool → false. Гарантира, че никога няма боклук, нито „недефинирано“.
2.6 [0] [""] — нулевата стойност на int и на string, а %q показва кавичките.
2.7 Println отпечатва и минава на нов ред. Printf отпечатва с шаблон с % и не минава
сама на нов ред. Sprintf използва същия шаблон, но връща текста, вместо да го отпечата.
2.8 nil означава „нищо“ / „празно“. if err != nil пита „грешката не е ли празна?“, тоест
„имаше ли грешка?“.
2.9 Трите:
- Липсва
import "fmt", а се използваfmt.Println. puerto := 8080използва:=върху променлива, която вече съществува → трябва да е=.puertoсе декларира и никога не се използва (отпечатва се самоnombre) →declared and not used.
Упражнения с код
🔴 Тези седем упражнения все още нямат еталонно решение — то ще бъде добавено в по-късна версия. Не е измислен код за решение, за да не се публикува пример, без първо да е изпълнен.
2.10 Напиши програма, която декларира името ти, възрастта ти и дали учиш, или работиш, и ги отпечатва на
три реда с Printf, като използваш правилния глагол за всеки тип.
2.11 Напиши func celsiusAFahrenheit(c float64) float64 и я изпробвай с 0, 37 и 100. Формулата е
f = c*9/5 + 32. Внимание: ако напишеш c*9/5 с цели числа, резултатът се отрязва. Защо тук това не
се случва?
2.12 Напиши func esPar(n int) bool. Подсказка: операторът % дава остатъка от деление, така че
n % 2 == 0 е вярно за четните числа.
2.13 Напиши func raizCuadrada(n float64) (float64, error), която връща грешка, ако n е отрицателно.
Използвай math.Sqrt (трябва ти import "math"). Изпробвай я с 16 и с -4, като обработиш грешката и в двата
случая.
2.14 Вземи Фиг. 2.10 и ѝ добави колона, която казва SI или NO според това дали портът е 443.
Трябва ти нова функция и да промениш шаблона на Sprintf.
2.15 (Намери грешката) Всеки от тези фрагменти има проблем. Кажи го, без да компилираш, а после компилирай, за да потвърдиш:
// (a)
resultado := dividir(10, 2)
// (b)
func sumar(a, b) int { return a + b }
// (c)
var x int = "5"
// (d)
fmt.Printf("el total es %d")
2.16 (Проект на курса) Това е първата стъпка от програмата, която ще изграждаш през целия курс. Напиши програма, която:
- Има функция
revisar(nombre string, puerto int, ms int) string, която връща ред от отчета. - Има функция
clasificar(ms int) string. - Отпечатва заглавен ред и пет услуги.
- Накрая отпечатва колко от петте са били
"rapido". Ще ти трябват променлива брояч иif.
Запази я: в урок 3 ще я преустроиш със structs.
Как разбирам, че съм успял
- Компилира и пусна, сам и без копиране/поставяне, фигури 2.1 до 2.10 от този урок, и получи точно показания изход.
- Можеш да обясниш, без да гледаш текста, защо Go е компилиран език и каква практическа последица има това за хващането на грешки преди продукция.
- Знаеш наизуст кога да използваш
:=и кога=и каква грешка дава компилаторът, ако сбъркаш. - Можеш да назовеш четирите основни типа (
string,int,float64,bool) и нулевата стойност на всеки от тях, без да поглеждаш таблицата. - Написа и пусна своя собствена версия на упражнение 2.16 (първата стъпка на
revisor): компилира се, отпечатва заглавния ред, петте реда и броя на бързите услуги. - Можеш да обясниш с две изречения защо
if err != nilсе появява навсякъде в кода на Go и какъв проблем избягва в сравнение с изключенията на други езици.
Отвори bitacora.md и запиши две неща: грешката на компилатора, която ти е било най-трудно да
разбереш, и нещо, което те е изненадало. След три седмици ще ти изглежда очевидно и няма да помниш
защо ти е било трудно — а точно това си струва да е записано.
Резюме
- Go е компилиран език: превежда целия ти код веднъж и създава самостоятелен изпълним файл.
- Всеки файл принадлежи на пакет; пакетът
mainе единственият, който създава изпълним файл. - Изпълнението започва от функцията
main. importвнася пакети; Go не зарежда нищо по подразбиране.:=декларира и присвоява;=само присвоява.- Go не се компилира, ако декларираш променлива и не я използваш, нито ако смесваш типове.
- Четирите основни типа са
string,int,float64иbool. - Нулевата стойност гарантира, че всяка променлива се ражда с валидна стойност:
"",0,0,false. Printlnотпечатва с нов ред;Printfизползва шаблон с%;Sprintfвръща текста, вместо да го отпечата.- Функция на Go може да върне няколко стойности, а стандартният шаблон е да се върне
(resultado, error). nilозначава „нищо“.if err != nilе идиоматичният начин да провериш дали е имало грешка, и най-често писаният ред в Go.go runкомпилира и изпълнява, без да оставя файл;go buildоставя изпълнимия файл.
За допълнително четене
- A Tour of Go — официална, интерактивна. Мини частта „Basics“ дотам, докъдето си стигнал в този урок.
- Go by Example — Variables и
Go by Example — Multiple Return Values — същият
шаблон
(resultado, error)с минимални програми, които се изпълняват. - Effective Go — още не е нужно да го четеш целия, но прегледай го, ако нещо от този урок ти се е сторило произволно правило: там е обяснението защо.
Ако нещо не ти е станало ясно: прочети цялото съобщение за грешка (Go обикновено казва реда, колоната и какво е очаквал), потърси понятието в Go by Example и запиши въпроса в дневника, дори да не го решиш. Записан въпрос може да се реши по-късно; забравен — не.
Термини от този урок
| компилатор | програма, която превежда изходен код в машинни инструкции |
| грешка при компилация | грешка, която пречи да се създаде изпълнимият файл; открива се преди изпълнението |
| функция | именуван блок от код, който получава параметри и може да връща стойности |
празен идентификатор (_) |
символ, който изхвърля стойност нарочно |
int, float64, string, bool |
четирите основни типа |
| компилиран / интерпретиран език | превежда всичко веднъж / ред по ред при всяко изпълнение |
main (функция) |
входна точка на програмата |
main (пакет) |
единственият пакет, който създава изпълним файл |
nil |
липса на стойност |
| пакет | група от свързан код |
| параметър | данни, които една функция получава |
Printf / Println / Sprintf |
отпечатване с шаблон / отпечатване с нов ред / връщане на текст |
| тип | вид данни, които една променлива може да пази |
| нулева стойност | валидна стойност, която получава всяка променлива, декларирана без стойност |
| променлива | именувано място в паметта, което пази данни |
форматиращ глагол (verb) (%d, %s, %q, %t, %v) |
празно място в шаблон на Printf |
Предпочитате имейл? Пишете ни на hola@habil.mx