Изучение Go — день 2

Мне следовало бы назвать это «часть 2», а не «день 2», потому что я узнал все эти вещи за один день, но мне потребовалось 4 дня, чтобы написать эти заметки, и они все еще не заполнены. Но написание также является частью обучения.

1. Циклы и операторы if

Циклы for loop и операторы if statements довольно просты в использовании. Но чтобы использовать их правильно, нужно понимать две вещи: блоки и области видимости.

Что такое блок?

Код в Go можно разделить на сегменты, которые называются блоками. Блоки обычно представляют собой части кода между фигурными скобками. Они могут быть вложенными. Когда мы создаем цикл for, все, что находится между фигурными скобками, является блоком. Если мы помещаем операторы if внутрь цикла for, каждая часть кода между усатыми (фигурными) скобками создает блок.

for num := 1; num <= 10; num++ {
    if num % 2 == 0 {
        fmt.Println(num, "is an even number.")
    } else if num % 2 != 0 {
    fmt.Println(num, "is an odd number.")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, в приведенном выше примере есть 3 блока кода.

Что такое область видимости?

Область видимости переменных связана с блоками. Когда мы объявляем переменную, она будет узнаваема только в пределах блока, в котором мы ее объявили, и блоков, вложенных в этот блок. Поэтому, когда мы объявляем переменную в одной части оператора if, она не будет работать в другой части if, а также за пределами пункта if-else.

Если я хочу немного изменить предыдущий код и добавить переменную с именем answer, то это будет выглядеть следующим образом:

for num := 1; num <= 10; num++ {        
    if num %2 == 0 {
        answer := "is an even number."
    } else if num%2 != 0 {
    answer := "is an odd number."       
    }       
    fmt.Println(num, answer)
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Go не позволяет мне сделать это. Для первых двух «ответов» он скажет, что переменная объявлена и никогда не используется. А на последний «ответ» он скажет, что это необъявленное имя.

Чтобы исправить это, мне нужно объявить переменную ответа в первом блоке — цикле for — вот так:

for num := 1; num <= 10; num++ {    
    var answer string   
    if num %2 == 0 {
    answer = "is an even number."
    } else if num%2 != 0 {
    answer = "is an odd number."        
    }       
    fmt.Println(num, answer)
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Что такое continue и break?

Иногда мы хотим завершить цикл при выполнении определенного условия. Тогда мы используем оператор break.
Представим, что мы ищем число, делящееся на 5 в диапазоне от 1 до 10 (10 включительно). И нас устраивает первое же полученное число.

for n := 1; n <= 10;n++ {       
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
    break
    } else {
    fmt.Println(n, "is not divided by 5")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Эта короткая программа будет выполняться только до тех пор, пока она не дойдет до самого первого числа, которое можно разделить на пять: 5.

После выполнения этого цикла (конечно, его нужно поместить внутрь функции, чтобы он работал в Go) мы увидим такой вывод:

1 не делится на 5
2 не делится на 5
3 не делится на 5
4 не делится на 5
5 делится на 5

Как мы видим, моя программа остановилась, не проверив все числа в диапазоне.

Continue не останавливает цикл, но если у нас есть что-то после continue внутри блока в этом операторе, он не будет проверять код, а только сразу перейдет к следующей итерации цикла.

for n := 1; n <= 10;n++ {       
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
    continue
        if (n == 5) {
        fmt.Println("It's 5.")
    }
    } else {
        fmt.Println(n, "is not divided by 5")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

// вывод
1 не делится на 5
2 не делится на 5
3 не делится на 5
4 не делится на 5
5 делится на 5
6 не делится на 5
7 не делится на 5
8 не делится на 5
9 не делится на 5
10 делится на 5

Вывод показывает, что блок после continue не был выполнен вообще.

2. Для всего есть пакет

До сих пор я не использовал много методов в Go, но заметил, что для использования почти всех функций и методов, предоставляемых Go, мне сначала нужно импортировать пакеты, которые их содержат.

Если я хочу напечатать вывод, мне нужна библиотека fmt, а затем одна из функций Print(). Если я хочу обрезать следующий символ строки, мне нужен пакет strings и функция TrimSpace().

Но все становится немного сложнее, когда мы хотим использовать методы, связанные со значениями определенного типа.

Например, когда мы хотим получить только год из даты, нам сначала нужно импортировать пакет time. Затем мы получим доступ к дате с помощью функции Now(), которую нужно присвоить переменной. И только после этого мы воспользуемся методом Year().

package main 

import (
    "fmt"
    "time"
)

func main() {
    var now time.Time = time.Now();
    var year int = now.Year()   
    fmt.Println(year)   
}
Вход в полноэкранный режим Выход из полноэкранного режима

В этой функции тип первой переменной (now) — time.Time. Тип второй переменной (year) — целое число.

Некоторые из этих методов возвращают два значения, в то время как нам нужна только одна переменная.
Когда мы хотим получить ввод от пользователя, нам понадобится пакет bufio и функция NewReader(). В приведенном ниже коде я присваиваю bufio.NewReader(os.Stdin) переменной reader.

reader := bufio.NewReader(os.Stdin)

Тип этой переменной — bufio.Reader. Это что-то очень новое для меня. Я пытался вывести переменную reader и она показала мне что-то вроде этого &{[0…..0] 0x0000e010 00 -1 -1}. На данный момент я понимаю только то, что это что-то двоичное.

Для того чтобы иметь возможность использовать ввод из командной строки, следующим шагом будет присвоение переменной reader другой переменной, но также мы должны вызвать другой метод — ReadString.

input := reader.ReadString('n') // it's got an error

Руна n в скобках означает конец ввода данных.

Но мы еще не готовы. Метод ReadString хочет вернуть нам два значения, но у нас назначена только одна переменная. Одно значение — это ввод из командной строки, а другое значение обычно является информацией об ошибках. Теперь нам нужно обработать ошибку.

Мы сделаем это, добавив вторую переменную:

fmt.Print("Give me a number: ")
reader := bufio.NewReader(os.Stdin)

input, err := reader.ReadString('n') // error again

fmt.Println(input)
Вход в полноэкранный режим Выйти из полноэкранного режима

Код больше не будет компилироваться, потому что мы всегда должны использовать все объявленные значения. У нас есть два варианта.

  1. Использовать _ (подчеркивание) вместо err.

input, _ := reader.ReadString('n')

Таким образом, мы будем игнорировать всю информацию об ошибках из входных данных.

  1. Или мы можем обработать ошибку. Теперь нам нужен еще один пакет log и функция Fatal(), которая выведет нам, какая у нас ошибка, и завершит нашу программу.
input, err := reader.ReadString('n')   
log.Fatal(err)  
fmt.Println(input)
Вход в полноэкранный режим Выход из полноэкранного режима

Но опять же, использование log.Fatal(err) таким образом остановит программу, даже если пользователь командной строки что-то набрал.

Мы должны использовать оператор if, чтобы показывать только те ошибки, которые не являются nil. (nil — нулевое значение — все, что я знаю о nil на данный момент)

пакет main

import (
    "fmt"
    "bufio"
    "os"
    "log"
)

func main() {
    fmt.Print("Give me a number: ")
    reader := bufio.NewReader(os.Stdin)

    input, err := reader.ReadString('n')
    if err != nil {
        log.Fatal(err)
    }   
    fmt.Println(input)
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Так много строк, чтобы вывести только входные данные из терминала.

Еще одна вещь, чтобы сделать пакеты более запутанными 😉

Иногда мы хотим импортировать пакет, например, rand для генерации случайных чисел, но в части кода с импортом нам нужно указать путь импорта — math/rand. Это происходит потому, что пакеты, относящиеся к схожим категориям, группируются. А пакет rand сгруппирован вместе с другими библиотеками для математических операций.

package main 

import (
    "fmt"
    "math/rand"
)

func main() {
    target := rand.Intn(100) + 1
    fmt.Println(target)
}
Вход в полноэкранный режим Выход из полноэкранного режима

Приведенный выше код генерирует случайное число в диапазоне от 1 до 100. Но только в теории. Если мы захотим его запустить, то увидим одно и то же число. Каждый раз, когда мы будем его запускать.

Как генерировать больше случайных чисел? Это история для другого случая.

Оцените статью
Procodings.ru
Добавить комментарий