Перечислим здесь важные особенности, про которые следует помнить при программированиии на Go.
Язык Go является регистрозависимым: большие и маленькие буквы различаются.
Арифметические операции обозначаются так: сложение (+), вычитание (-), умножение (*), деление (/), взятие остатка (%).
Операции сравнения обозначаются так: равно (==), не равно (!=), меньше (<), больше (>), меньше или равно (<=), больше или равно (>=).
Логические операции: не (!), и (&&), или (||).
Текстовые константы берутся в двойные кавычки. Одиночные символы – в одинарные. Внутри текстовых и символьных констант допустимы экранированные последовательности, такие как символ перехода на следующую строчку (\n), символ табуляции (\t), двойная кавычка (\"), одинарная кавычка (\'). Экранирование можно отключить, взяв текст в обратные кавычки. При этом внутри текста допускается явный переход на следующую строчку.
Комментарии в программе бывают однострочные (выделяются //) и блочные (начинаются /* и заканчиваются */).
Каждая команда языка заканчивается точкой-с-запятой (;), но от программиста не требуется их ставить: компилятор языка их ставит самостоятельно. При написании некоторых конструкций эта тонкость существенна: фигурные скобки нужно ставить так, как показано в примерах.
Команда изменения значения (=) обозначается одинарным знаком «равно». Обозначение двоеточие-равно (:=) используется для создания новых переменных.
Есть команды увеличения (+=), уменьшения (-=), домножения (*=) и т.д. Также есть команды увеличения на 1 (постфиксный ++) и уменьшения на 1 (постфиксный --).
Программа состоит из нескольких пакетов. Каждый пакет содержит список используемых пакетов, а также – определения констант, глобальных переменных, типов данных и подпрограмм.
Точка входа в программу должна называться main и содержаться в пакете main. В соответствии с этим «скелет» программы выглядит так:
package main
func main() {
// программа начинает работу отсюда
}Здесь приведён пример программы, складывающей два числа, запрошенных у пользователя.
package main
import "fmt" // используем пакет fmt, в котором содержатся операции ввода/вывода
func main() {
fmt.Println("Введите два числа")
var x, y int // создание двух целочисленных переменных
fmt.Scan(&x,&y) // считывание введённых пользователем значений в эти переменные
fmt.Println(x,"+",y,"=",x+y)
}Эта программа применяет подпрограммы Println и Scan, определённые в пакете fmt. Следует обратить внимание на амперсанды перед аргументами Scan: если их не поставить, то числа не будут считаны в указанные переменные. Смысл этих амперсандов мы проясним в следующей главе.
Переменная представляет собой имя для некоторого объекта. Go относится к статически типизированным языкам: это означает, что каждая переменная имеет свой тип и может именовать только объект такого типа.
Перечислим несколько основных типов:
Целочисленные типы: int, int8, int16, int32, int64. Различаются количеством бит, отведённым на хранение числа.
Целые неотрицательные типы: uint, byte, uint8, uint16, uint32, uint64. Тип byte – полный синоним uint8.
Текстовый тип: string.
Символьный тип: rune. Является полным синонимом int32. Символы отождествляются с их числовыми кодами в кодировке UTF32.
Логический тип: bool. Имеет два значения: true и false.
Числа с плавающей точкой: float32 и float64. Первый из этих типов позволяет хранить число с точностью примерно 7 десятичных подряд идущих цифр, второй – с точностью примерно 14 десятичных подряд идущих цифр.
Использование одного числового типа вместо другого похожего не допускается. Например, код
var x int64 = 2
var y int32 = 3
var z = x + yне скомпилируется. Название типа можно использовать в качестве операции приведения к этому типу. Например, следующее вполне допустимо:
var x int64 = 2
var y int32 = 3
var z = x + int64(y) // аргументы и результат типа int64Создать переменную можно одним из следующих способов:
В переменную попадает нулевое значение: var название тип
В переменную попадает указанное значение: var название = значение или var название тип = значение
Сокращение для предыдущего: название := значение
Важно помнить, что переменная живёт только до конца блока (обозначаемого парой фигурных скобок), в котором она определена.
Условная конструкция в языке Go имеет довольно стандартный синтаксис:
if x > 0 {
// если x положителен
} else if x == 0 {
// в противном случае, если x равен 0
} else {
// в противном случае
}Важно помнить, что слово else должно начинаться на той же строчке, что и закрывающаяся фигурная скобка.
Вечный цикл (можно прервать командой break):
for {
// тело цикла
}Цикл «пока выполнено условие»:
for условие {
// тело цикла
}Цикл с инициализацией и модификацией состояния:
for инициализация; условие; модификация {
// тело цикла
}Последняя из этих разновидностей обычно применяется в следующей форме:
for i := 0; i < 10; i += 1 {
// тело цикла; будет выполнено десять раз
}Любая сколько-нибудь сложная программа основывается на более простых подпрограммах, каждая из которых решает какую-то конкретную подзадачу. В языке Go подпрограммы традиционно называются функциями. Каждая функция определяется так:
func название(вход1 тип1, вход2 тип2, ...) (выход1 тип1, выход2 тип2, ...) {
// тело функции
}Например, вот функция, вычисляющая остаток и неполное частное от деления целых чисел:
func ModDiv(a int, b int) (mod int, div int) {
mod = a % b
div = a / b
return // команда return завершает исполнение подпрограммы
}В языке Go довольно редко именуют выходы. Более идиоматичен следующий код:
func ModDiv(a int, b int) (int,int) {
return a%b, a/b
}В качестве примера определения собственных функций рекомендуется изучить решения упражнений 1 и 6 ниже.
Реальность такова, что в процессе обучения Вам придётся читать (или даже писать) программы на языке Паскаль. К счастью, та реализация языка Паскаль, которая сейчас используется повсеместно в школах России (а именно, PascalABC.NET), переняла некоторые возможности сколько-нибудь современных языков программирования. По этой причине разница между простейшими программами на PascalABC.NET и на Go минимальна.
Перечислим основные отличия:
Язык Go чувствителен к регистру, Паскаль – нет.
В языке Go каждая команда заканчивается (неявной) точкой-с-запятой; в Паскале точка-с-запятой является разделителем команд: в конце блока её можно не ставить.
В языке Go блоки выделяются фигурными скобками; в Паскале блоки выделяются словами begin и end.
В языке Go точкой входа является функция main; в Паскале точкой входа является блок кода между begin и end. на внешнем уровне.
В языке Go есть ровно один тип подпрограмм: функции; в Паскале подпрограммы, не имеющие результата, называются процедурами.
В языке Go есть команда преждевременного выхода из функции return. Её использование обязательно, если функция имеет результат. В Паскале результат записывается в переменную с названием, совпадающим с названием функции. Преждевременный выход осуществляется специальной «процедурой» Exit.
Сравнение и присваивание в Go обозначаются знаками == и =, а в Паскале – знаками = и :=.
В Паскале по-другому устроены циклы.
Некоторые упражнения из нижеприведённых разобраны также и на языке Паскаль.
В каждой из этих задач на вход подаётся одно целое положительное число (далее – x), не превышающее миллиарда. Требуется напечатать
Наибольший общий делитель и наименьшее общее кратное чисел x и 20172017.
YES, если x простое, NO – в противном случае.
Сумму всех делителей числа x.
Число с порядковым номером x в последовательности 1 2 2 3 3 3 4 4 4 4 …
Тысячу знаков после запятой числа 1/x.
Во всех следующих задачах формат входных данных: число N, затем N чисел, которые требуется обработать. Требуется напечатать
Число с наименьшей суммой цифр.
Число с наибольшей суммой делителей.
Дисперсию (среднее арифметическое квадратов отклонений от среднего арифметического).
Самое частовстречающееся число (на данном этапе это упражнение довольно сложное).
Во всех решениях строчки package main и import "fmt" считаются написанными в начале программы.
// Упражнение 1
func GCD(a, b int) int {
// алгоритм Евклида
for b != 0 {
a,b = b,a%b
}
return a
}
func main() {
var x int
fmt.Scan(&x)
a,b := x,20172017 // эти a,b никакого отношения к a,b из функции GCD не имеют!
gcd := GCD(a,b)
lcm := (a / GCD(a,b)) * b
fmt.Println(gcd, lcm)
}// Для сравнения упражнение 1 на Паскале
function GCD(a,b: integer): integer; begin
while b <> 0 do begin
(a,b) := (b,a mod b)
end;
GCD := a;
end;
begin
var x: integer;
read(x);
(var a, var b) := (x, 20172017);
var gcd_ab := GCD(a,b);
var lcm_ab := (a div GCD(a,b)) * b;
println(gcd_ab, lcm_ab);
end.// Упражнение 2
func main() {
var x int
fmt.Scan(&x)
if x == 1 {
fmt.Println("NO")
return // main -- такая же функция, как и все остальные; её тоже можно преждевременно завершить
}
found := false
for d := 2; d*d <= x; d++ {
if x % d == 0 {
fmt.Println("NO")
found = true
break
}
}
if !found {
fmt.Println("YES")
}
}// Упражнение 3
func main() {
var x int
fmt.Scan(&x)
sum := 0
for d := 1; d <= x; d++ {
if x % d == 0 {
sum += d
}
}
fmt.Println(sum)
}// Упражнение 4
func main() {
var x int
fmt.Scan(&x)
n := 1
k := 1
for step := 1; step < x; step++ {
if k == n {
k, n = 1, n+1
} else {
k++
}
}
fmt.Println(n)
}// Упражнение 5
func main() {
var x int
fmt.Scan(&x)
d := 0
if x > 1 {d = 10}
for i := 0; i < 1000; i++ {
fmt.Print(d / x)
d = 10*(d % x)
}
fmt.Println() // после вывода данных принято переходить на следующую строчку
}// Упражнение 6
func SumDigits(n int) int {
sum := 0
for n > 0 {
sum += n % 10
n = n / 10
}
return sum
}
func main() {
var n int
fmt.Scan(&n)
var optimal int // кандидат на звание "самого лучшего" числа
fmt.Scan(&optimal)
for i:=1; i < n; i++ {
var x int
fmt.Scan(&x)
// наглядная иллюстрация удобств, предоставляемых собственноручно определённой функцией
if SumDigits(x) < SumDigits(optimal) {
optimal = x
}
}
fmt.Println(optimal)
}@ 2016 arbrk1, all rights reversed