Update 02.3.md

Мелкие правки и подсветка синтаксиса
This commit is contained in:
Bloom
2017-05-26 13:05:48 +07:00
committed by GitHub
parent 0440f3b411
commit d4238bdfd7

View File

@@ -11,183 +11,182 @@
`if`, вероятно, будет часто встречающимся ключевым словом в Ваших программах. Если условие, указанное в нем, удовлетворяется, выполняется блок кода, а если не удовлетворяется, то выполняется что-то другое.
В Go `if` не нуждается в скобках.
if x > 10 {
fmt.Println("x больше 10")
} else {
fmt.Println("x меньше или равно 10")
}
```Go
if x > 10 {
fmt.Println("x больше 10")
} else {
fmt.Println("x меньше или равно 10")
}
```
Наиболее полезной чертой `if` в Go является то, что перед выражением условия может находиться выражение присваивания. Область видимости переменных, инициализированных в этом выражении, ограничена блоком, относящимся к `if`:
```Go
// определяем x, затем проверяем, больше ли x, чем 10
if x := computedValue(); x > 10 {
fmt.Println("x больше 10")
} else {
fmt.Println("x меньше или равно 10")
}
// определяем x, затем проверяем, больше ли x, чем 10
if x := computedValue(); x > 10 {
fmt.Println("x больше 10")
} else {
fmt.Println("x меньше или равно 10")
}
// А этот код не скомпилируется
fmt.Println(x)
// А этот код не скомпилируется
fmt.Println(x)
```
Для множественных условий используйте if-else:
if integer == 3 {
fmt.Println("Целое число равно 3")
} else if integer < 3 {
fmt.Println("Целое число меньше 3")
} else {
fmt.Println("Целое число больше 3")
}
```Go
if integer == 3 {
fmt.Println("Целое число равно 3")
} else if integer < 3 {
fmt.Println("Целое число меньше 3")
} else {
fmt.Println("Целое число больше 3")
}
```
### goto
Go has a `goto` keyword, but be careful when you use it. `goto` reroutes the contro to a previously defined `label` within the body of same code block.
В Go есть ключевое слово `goto`, но, исопльзуя его, будьте осторожными. `goto` перенаправляет управление потоком команд к заранее определенной `метке` внутри блока кода, в котором оно находится.
func myFunc() {
i := 0
Here: // Метка заканчивается на ":"
fmt.Println(i)
i++
goto Here // Переходим к метке "Here"
}
```Go
func myFunc() {
i := 0
Here: // Метка заканчивается на ":"
fmt.Println(i)
i++
goto Here // Переходим к метке "Here"
}
```
Названия меток чувствительны к регистру.
### for
`for` - самый мощный способ управления потоком в Go. Он может работать с данными в циклах и итеративных операциях, так же, как `while`.
for expression1; expression2; expression3 {
//...
}
```Go
for expression1; expression2; expression3 {
//...
}
```
`expression1`, `expression2` и `expression3` - это выражения, где `expression1` и `expression3` - определения переменных или значений, возвращаемых функциями, а `expression2` - условное выражение. `expression1` выполняется один раз перед запуском цикла, а `expression3` выполняется после каждого шага цикла.
Примеры, однако, полезнее слов:
```Go
package main
import "fmt"
package main
import "fmt"
func main(){
sum := 0;
for index:=0; index < 10 ; index++ {
sum += index
}
fmt.Println("sum равно ", sum)
}
// Printsum равно 45
func main(){
sum := 0;
for index:=0; index < 10 ; index++ {
sum += index
}
fmt.Println("sum равно ", sum)
}
// Printsum равно 45
```
Иногда нам могут понадобиться множественные присваивания, но в Go нет оператора `,`, поэтому можно использовать параллельное присваивание типа `i, j = i + 1, j - 1`.
Можно опускать `expression1` и `expression3`, если в них нет необходимости:
sum := 1
for ; sum < 1000; {
sum += sum
}
```Go
sum := 1
for ; sum < 1000; {
sum += sum
}
```
Опускаем также `;`. Знакомо? Да, такая конструкция идентична `while`.
sum := 1
for sum < 1000 {
sum += sum
}
```Go
sum := 1
for sum < 1000 {
sum += sum
}
```
В циклах есть две важные операции `break` и `continue`. `break` прекращает выполнение цикла, а `continue` прекращает выполнение текущей итерации цикла и начинает выполнять следующую. Если у Вас есть вложенные циклы, используйте `break` вместе с метками.
for index := 10; index>0; index-- {
if index == 5{
break // или continue
}
fmt.Println(index)
}
// break печатает 10、9、8、7、6
// continue печатает 10、9、8、7、6、4、3、2、1
```Go
for index := 10; index>0; index-- {
if index == 5{
break // или continue
}
fmt.Println(index)
}
// break печатает 10、9、8、7、6
// continue печатает 10、9、8、7、6、4、3、2、1
```
`for` может читать данные из `срезов` и `карт` при помощи ключевого слова `range`.
for k,v:=range map {
fmt.Println("Ключ карты:",k)
fmt.Println("Значение карты:",v)
}
```Go
for k,v:=range map {
fmt.Println("Ключ карты:",k)
fmt.Println("Значение карты:",v)
}
```
Так как в Go может возвращаться сразу несколько значений, а если не использовать какое-либо присвоенное значение, возвращается ошибка компиляции, можно использовать `_`, чтобы отбросить ненужные возвращаемые значения:
for _, v := range map{
fmt.Println("Значение элемента карты:", v)
}
```Go
for _, v := range map{
fmt.Println("Значение элемента карты:", v)
}
```
### switch
Иногда выходит так, что для того, чтобы реализовать какую-нибудь программную логику, приходится использовать слишком много выражений `if-else`, что приводит к том у, что код становится трудно читать и поддерживать в будущем. Самое время воспользоваться ключевым словом `switch`, чтобы решить эту проблему!
switch sExpr {
case expr1:
какие-нибудь инструкции
case expr2:
другие инструкции
case expr3:
еще инструкции
default:
другой код
}
Иногда выходит так, что для того, чтобы реализовать какую-нибудь программную логику, приходится использовать слишком много выражений `if-else`, что приводит к тому, что код становится трудно читать и поддерживать в будущем. Самое время воспользоваться ключевым словом `switch`, чтобы решить эту проблему!
```Go
switch sExpr {
case expr1:
какие-нибудь инструкции
case expr2:
другие инструкции
case expr3:
еще инструкции
default:
другой код
}
```
Тип `sExpr`, `expr1`, `expr2`, and `expr3` должен быть один и тот же. `switch` очень гибок. Условия не обязаны быть постоянными, условия проверяются сверху вниз, пока не будет достигнуто условие, которое удовлетворяется. Если после ключевого слова `switch` нет выражения, ищется `true`.
i := 10
switch i {
case 1:
fmt.Println("i равно 1")
case 2, 3, 4:
fmt.Println("i равно 2, 3 или 4")
case 10:
fmt.Println("i равно 10")
default:
fmt.Println("Все, что я знаю - это то, что i - целое число")
}
```Go
i := 10
switch i {
case 1:
fmt.Println("i равно 1")
case 2, 3, 4:
fmt.Println("i равно 2, 3 или 4")
case 10:
fmt.Println("i равно 10")
default:
fmt.Println("Все, что я знаю - это то, что i - целое число")
}
```
В пятой строке мы поместили несколько значений в один `case`; нам также не надо писать ключевое слово `break` в конце тела `case`. При выполнении какого-либо условия цикл прекратитсяавтоматически. Если Вы хотите продолжать проверку, нужно использовать выражение `fallthrough`.
integer := 6
switch integer {
case 4:
fmt.Println("integer <= 4")
fallthrough
case 5:
fmt.Println("integer <= 5")
fallthrough
case 6:
fmt.Println("integer <= 6")
fallthrough
case 7:
fmt.Println("integer <= 7")
fallthrough
case 8:
fmt.Println("integer <= 8")
fallthrough
default:
fmt.Println("default case")
}
```Go
integer := 6
switch integer {
case 4:
fmt.Println("integer <= 4")
fallthrough
case 5:
fmt.Println("integer <= 5")
fallthrough
case 6:
fmt.Println("integer <= 6")
fallthrough
case 7:
fmt.Println("integer <= 7")
fallthrough
case 8:
fmt.Println("integer <= 8")
fallthrough
default:
fmt.Println("default case")
}
```
Эта программа выведет следующее:
integer <= 6
integer <= 7
integer <= 8
default case
```
integer <= 6
integer <= 7
integer <= 8
default case
```
## Функции
Чтобы определить функцию, используйте ключевое слово `func`.
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// тело функции
// возврат множества значений
return value1, value2
}
```Go
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// тело функции
// возврат множества значений
return value1, value2
}
```
Мы можем сделать вывод из примера выше:
- Нужно использовать ключевое слово `func` длы того, чтобы определить функцию `funcName`.
@@ -199,31 +198,31 @@ Go has a `goto` keyword, but be careful when you use it. `goto` reroutes the con
- Если функция возвращает значения, нужно обязательно использовать выражение `return` где-нибудь в теле функции.
Давайте рассмотрим какой-нибудь практический пример: (вычисление максимального значения)
```Go
package main
import "fmt"
package main
import "fmt"
// возвращаем наибольшее значение из a и b
func max(a, b int) int {
if a > b {
return a
}
return b
}
// возвращаем наибольшее значение из a и b
func max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
x := 3
y := 4
z := 5
func main() {
x := 3
y := 4
z := 5
max_xy := max(x, y) // вызываем функцию max(x, y)
max_xz := max(x, z) // вызываем функцию max(x, z)
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) // вызываем функцию непосредственно отсюда
}
max_xy := max(x, y) // вызываем функцию max(x, y)
max_xz := max(x, z) // вызываем функцию max(x, z)
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) // вызываем функцию непосредственно отсюда
}
```
В приведенном примере функция `max` имеет 2 аргумента, оба аргумента имеют тип `int`, поэтому для первого аргумента указание типа может быть опущено. Например, `a, b int` вместо `a int, b int`. Те же правили применимы для дополнительных аргументов. Имейте в виду, что `max` возвращает только одно значение, поэтому нам нужно указать только тип возвращаемого значения - такова краткая форма записи для таких случаев.
### Возврат множества значений
@@ -231,71 +230,71 @@ Go has a `goto` keyword, but be careful when you use it. `goto` reroutes the con
Одна из вещей, в которых Go лучше, чем C - это то, что функции в Go могут возвращать несколько значений.
Приведем следующий пример:
```Go
package main
import "fmt"
package main
import "fmt"
// возвращаем результаты A + B и A * B
func SumAndProduct(A, B int) (int, int) {
// возвращаем результаты A + B и A * B
func SumAndProduct(A, B int) (int, int) {
return A+B, A*B
}
}
func main() {
x := 3
y := 4
func main() {
x := 3
y := 4
xPLUSy, xTIMESy := SumAndProduct(x, y)
xPLUSy, xTIMESy := SumAndProduct(x, y)
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}
```
В вышеприведенном примере два значения возвращаются без имен; также можно и дать им имена. Если мы именуем переменные, которые будут возвращаться, нам нужно лишь написать `return`, чтобы возвратить значения, так как то, что надо возвращать, уже определено в функции автоматически. Имейте в виду, что если Вы собираетесь использовать функцию вне пакета (что означает, что Вы должны именовать эту фунцкию с заглавной буквы), лучше указывавйте полную форму `return`; это сделает Ваш код более читаемым.
func SumAndProduct(A, B int) (add int, Multiplied int) {
add = A+B
Multiplied = A*B
return
}
```Go
func SumAndProduct(A, B int) (add int, Multiplied int) {
add = A+B
Multiplied = A*B
return
}
```
### Переменные аргументы
Go поддерживает переменные аргументы, что означает, что можно передать неопределенное количество аргументов в функцию.
func myfunc(arg ...int) {}
```Go
func myfunc(arg ...int) {}
```
`arg …int` говорит Go о том, что данная функция имеет неопределенное количество аргументов. Заметьте, что в функцию передаются аргументы типа `int`. В теле функции `arg` становится `срезом` элементов типа `int`.
for _, n := range arg {
fmt.Printf("И число равно: %d\n", n)
}
```Go
for _, n := range arg {
fmt.Printf("И число равно: %d\n", n)
}
```
### Передача аргументов по значению и указателю
Когда мы передаем в функцию аргументы, на самом деле она получает копию передаваемых переменных, поэтому любое изменение не затронет оригинал переданной переменной.
Чтобы доказать это, рассмотрим следующий пример:
```Go
package main
import "fmt"
package main
import "fmt"
// простая функция, прибавляющая 1 к a
func add1(a int) int {
a = a+1 // мы изменяем значение a
return a // возвращаем новое значение a
}
// простая функция, прибавляющая 1 к a
func add1(a int) int {
a = a+1 // мы изменяем значение a
return a // возвращаем новое значение a
}
func main() {
x := 3
func main() {
x := 3
fmt.Println("x = ", x) // должно печатать "x = 3"
fmt.Println("x = ", x) // должно печатать "x = 3"
x1 := add1(x) // вызываем add1(x)
x1 := add1(x) // вызываем add1(x)
fmt.Println("x+1 = ", x1) // должно печатать "x+1 = 4"
fmt.Println("x = ", x) // должно печатать "x = 3"
}
fmt.Println("x+1 = ", x1) // должно печатать "x+1 = 4"
fmt.Println("x = ", x) // должно печатать "x = 3"
}
```
Видите? Несмотря на то, что мы вызвали функцию `add1` с `x`, изначальное значение `x` не изменилось.
Причина очерь проста: когда мы вызвали `add1`, мы передали в нее копию `x`, а не сам `x`.
@@ -303,124 +302,123 @@ Go поддерживает переменные аргументы, что оз
Теперь Вы можете спросить, как передать в функцию сам `x`?
В этом случе нам нужно использовать указатели. Мы знаем, что переменные хранятся в памяти и у них есть адреса. Итак, если мы хотим изменить значение переменной, мы меняем значение, находящееся в памяти по соответствующему ей адресу. Поэтому, для того, чтобы изменить значение `x`, `add1` должна знать адрес `x` в памяти. Здесь мы передаем `&x` в функцию и меняем тип аргумента на тип указателя `*int`. Мы передаем в функцию копию указателя, не копию значения.
```Go
package main
import "fmt"
package main
import "fmt"
// простая функция, которая прибавляет 1 к a
func add1(a *int) int {
*a = *a+1 // мы изменяем a
return *a // мы возвращаем значение a
}
// простая функция, которая прибавляет 1 к a
func add1(a *int) int {
*a = *a+1 // мы изменяем a
return *a // мы возвращаем значение a
}
func main() {
x := 3
func main() {
x := 3
fmt.Println("x = ", x) // должно печатать "x = 3"
fmt.Println("x = ", x) // должно печатать "x = 3"
x1 := add1(&x) // вызываем add1(&x), передаем значение адреса памяти для x
x1 := add1(&x) // вызываем add1(&x), передаем значение адреса памяти для x
fmt.Println("x+1 = ", x1) // должно печатать "x+1 = 4"
fmt.Println("x = ", x) // должно печатать "x = 4"
}
fmt.Println("x+1 = ", x1) // должно печатать "x+1 = 4"
fmt.Println("x = ", x) // должно печатать "x = 4"
}
```
Зная все это, можно изменять значение `x` в функциях. Зачем использовать указатели? Каковы преимущества?
- Это позволяет многим функциям работать с одной переменной.
- Low cost by passing memory addresses (8 bytes), copy is not an efficient way, both in terms of time and space, to pass variables.
- Низкая стоимость выполнения благодаря тому, что передаются лишь адреса памяти (8 байт); копирование самих переменных не является эффективным как с точки зрения времени, так и объема памяти.
- `string`, `slice`, `map` - это ссылочные типы, поэтому они передаются в функцию как указатели по умолчанию. (Внимание: Если Вам нужно изменить длину `среза(slice)`, нужно явно передать срез как указатель)
### defer
В Go есть хорошо спроектированное ключевое слово `defer`. В одной функции может быть много выражений `defer`; они будут выполняться в обратном порядке в тот момент, когда процесс выполнения программы дойдет до конца функции. Рассмотрим случай: когда программа открывает какие-либо файлы, они затем должны быть закрыты перед тем, как функция закончит свою работу с ошибкой. Давайте взглянем на примеры:
```Go
func ReadWrite() bool {
file.Open("file")
// Что-нибудь делаем (failureX и failureY - условия, свидетельствующие о том, что произошли ошибки - прим. переводчика на русский)
if failureX {
file.Close()
return false
}
func ReadWrite() bool {
file.Open("file")
// Что-нибудь делаем (failureX и failureY - условия, свидетельствующие о том, что произошли ошибки - прим. переводчика на русский)
if failureX {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
}
file.Close()
return true
}
```
Мы видим, что один и тот же код повторился несколько раз. `defer` просто решает эту проблему. Оно не только помогает Вам писать чистый код, но и делает его более читаемым.
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}
```Go
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}
```
Если присутствует больше одного `defer`, они будут выполняться в обратном порядке. Следующий пример выведет `4 3 2 1 0`.
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
```Go
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
```
### Функции как значение и типы
В Go функции также являются переменными, мы можем использовать `type`, чтобы их определять. Функции с идентичными подписями являются функциями одного типа:
type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])
```Go
type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])
```
В чем преимущества такого способа? Ответ состоит в том, что это позволяет передавать функции как значения в другие функции.
```Go
package main
import "fmt"
package main
import "fmt"
type testInt func(int) bool // определяем тип переменной "функция"
type testInt func(int) bool // определяем тип переменной "функция"
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
}
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
}
// передаем функцию `f` как аргумент в другую функцию
// передаем функцию `f` как аргумент в другую функцию
func filter(slice []int, f testInt) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
func filter(slice []int, f testInt) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
func main(){
slice := []int {1, 2, 3, 4, 5, 7}
fmt.Println("Срез = ", slice)
odd := filter(slice, isOdd) // используем функции как значения
fmt.Println("Нечетные элементы среза: ", odd)
even := filter(slice, isEven)
fmt.Println("Четные элементы среза: ", even)
}
Это свойство очень полезно, когда мы используем интерфейсы. Как мы можем видеть, `testInt` - это переменная, имеющая тип "функция", аргументы и возвращаемые значение `filter` те же самые, что и `testInt` (здесь не согласен с оригиналом - прим. переводчика на русский). Поэтому мы можем применять в своих программах сложную логику, подерживая гибкость нашего кода.
func main(){
slice := []int {1, 2, 3, 4, 5, 7}
fmt.Println("Срез = ", slice)
odd := filter(slice, isOdd) // используем функции как значения
fmt.Println("Нечетные элементы среза: ", odd)
even := filter(slice, isEven)
fmt.Println("Четные элементы среза: ", even)
}
```
Это свойство очень полезно, когда мы используем интерфейсы. Как мы можем видеть, `testInt` - это переменная, имеющая тип "функция", аргументы и возвращаемые значение `filter` те же самые, что и `testInt` (здесь не согласен с оригиналом - прим. переводчика на русский)(имелось ввиду не `filter`, а `isOdd` и `isEven` - дополнительное примечание от сообщества). Поэтому мы можем применять в своих программах сложную логику, поддерживая гибкость нашего кода.
### Panic и Recover
@@ -431,34 +429,33 @@ Panic - это встроенная функция, которая прерыа
Recover - это встроенная функция для восстановления `горутин` из состояния panic. Нормально будет вызывать `recover` в функциях `defer`, так как обычные функции не буду выполняться, если программа находится в состоянии panic. Эта функция получает значение `panic`, если программа находится в состоянии panic, и `nil`, если не находится.
Следующий пример показывает, как использовать `panic`.
```Go
var user = os.Getenv("USER")
var user = os.Getenv("USER")
func init() {
if user == "" {
panic("не присвоено значение переменной $USER")
}
}
func init() {
if user == "" {
panic("не присвоено значение переменной $USER")
}
}
```
Следующий пример показывает, как проверять `panic`.
func throwsPanic(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
b = true
}
}()
f() // если f вызывает panic, включается recover
return
}
```Go
func throwsPanic(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
b = true
}
}()
f() // если f вызывает panic, включается recover
return
}
```
### функции `main` и `init`
В Go есть две зарезервированные функции - `main` и `init`, причем `init` может быть использована во всех пакетах, а `main` - только в пакете `main`. У этих функций не может быть аргументов и возвращаемых значений. Даже несмотря на то, что можно использовать несколько функций `init` в одном пакете, я настоятельно рекомендую использовать только по одной функции `init` для каждого пакета.
Программы на Go вызывают `init()` и `main()` автоматически, поэтому не нужно запускать их самому. Функция `init` может присутствовать в пакете, а может и не присутствовать, но, что касается функции `main`, то она обязана быть в `package main`, причем только в одном экземпляре.
Programs initialize and begin execution from the `main` package. If the `main` package imports other packages, they will be imported in the compile time. If one package is imported many times, it will be only compiled once. After importing packages, programs will initialize the constants and variables within the imported packages, then execute the `init` function if it exists, and so on. After all the other packages are initialized, programs will initialize constants and variables in the `main` package, then execute the `init` function inside the package if it exists. The following figure shows the process.
Программа инициализируется и начинает свое выполнение с пакета `main`. Если пакет `main` импортирует другие пакеты, они будут импортированы во время компиляции. Если один пакет импортируется несколько раз, он будет скомпилирован лишь единожды. После импорта пакета программа инициализирует переменные и константы в импортированном пакете, а затем выполнит функцию `init`, если она присутствует, и т.д. После того, как все пакеты будут проинициализированы, программа инициализирует константы и переменные в пакете `main`, а затем выполнит функцию `init` внутри него, если она имеется. Весь процесс изображен на следующем рисунке:
![](images/2.3.init.png?raw=true)
@@ -468,15 +465,15 @@ Programs initialize and begin execution from the `main` package. If the `main` p
### import
`import` очень часто используется в Go следующим образом:
import(
"fmt"
)
```Go
import(
"fmt"
)
```
Вот так используются функции из импортированного пакета:
```Go
fmt.Println("hello world")
```
`fmt` находится в стандртной библиотеке Go, он располагается в $GOROOT/pkg. Go поддерживает сторонние пакеты двумя способами:
1. Относительный путь
@@ -484,26 +481,23 @@ Programs initialize and begin execution from the `main` package. If the `main` p
2. Абсолютный путь
import "shorturl/model" // импортирует пакет, находящийся по пути "$GOPATH/pkg/shorturl/model"
Существует несколько сспециальных операторов, относящихся к импорту пакетов, и новички в них постоянно путаются:
Существует несколько специальных операторов, относящихся к импорту пакетов, и новички в них постоянно путаются:
1. Оператор "Точка".
Иногда мы можем видеть, как пакеты импортируются так:
1. Оператор "Точка". Иногда мы можем видеть, как пакеты импортируются так:
import(
. "fmt"
)
Оператор "Точка" означает, что можно опускать имя пакета при использовании функций этого пакета. Теперь `fmt.Printf("Hello world")` превращается в `Printf("Hello world")`.
2. Операция с псеводнимом.
Она изменяет имя пакета при использовании функций из него:
2. Операция с псевдонимом. Она изменяет имя пакета при использовании функций из него:
import(
f "fmt"
)
Теперь вместо `fmt.Printf("Hello world")` можно `f.Printf("Hello world")`.
3. Оператор `_`.
Этот оператор трудно понять без объяснения.
3. Оператор `_`. Этот оператор трудно понять без объяснения.
import (
"database/sql"