Константы

Неизменность - признак мастерства или ограниченности мышления, не знаю, чего именно...

Итак, мы отлично поработали над такой важной для любого языка программирования темой, как операторы. Были приведены разнообразные примеры, которые с одной стороны, оживили повествование, с другой же стороны, дали нам почувствовать, что нам уже становится тесно в рамках пройденного материала и хочется вкусностей - новых и разных. Что же, приступим незамедлительно!

Рассматривая ECR протокол HYPERCOM, мы узнали, что, по сути, этот протокол, как и многие подобные, базируется на ASCII. Таблица ASCII же, в свою очередь, содержит не только символы, представляющие цифры, знаки и буквы латиницы, но и так называемые управляющие символы, то есть такие символы в кодировке, которым не приписано графическое представление, но которые используются для управления устройствами, организации передачи данных и других целей. Любой из символов ASCII имеет свой байтовый эквивалент. Здесь наблюдается своеобразный дуализм в том, что всякий ASCII-based протокол может быть представлен как байтовый, что, в том числе, служит причиной появления "гибридных" протоколов, где часть байтов трактуется как управляющие или символьные ASCII, другая же - как наборы байтов, представляющих текст в иных кодировках, например cp-1251, или числа, приведенные к двух- или четырёхбайтовому виду. Таков, к примеру, аналогичный рассмотренному протоколу HYPERCOM, ECR протокол компании Банкомсвязь. Работая с управляющими символами ASCII, нам в первую очередь представилось удобным использовать константы.

Как объявляются константы?

Работа с константами в целом похожа на работу с переменными. В крупном проекте есть смысл вынести объявление констант в отдельный файл. Так же как переменные, константы могут быть объявлены как по одиночке, так и группами с применением круглых скобок.

package main

const DC2 = 0x12 //DEVICE CONTROL TWO

const (
	STX = 0x02 // START OF TEXT
	ETX = 0x03 // END OF TEXT	
	EOT = 0x04 // END OF TRANSMISSION
)
//Некоторые управляющие символы ASCII 

Существует также возможность группового объявления в строку

package main

const ACK, NAK = 0x06, 0x15 
// ACKNOWLEDGE and NEGATIVE ACKNOWLEDGE

Это только один из множества возможных примеров, который мы избрали как логичное продолжение рассмотренного ранее материала. В целом же константы окружают нас повсюду, олицетворяя саму по себе возможность существования нашего мира. Это может быть число Pi и постоянная Планка, гравитационная постоянная и скорость света в вакууме. В каждом подобном случае, будь то число Авогадро или простое количество сантиметров в дюйме - смело используем константы.

Генератор констант iota

Константы могут объявляться следующим способом:

package main

import "fmt"

const (
    a = 1
    b
    c = "one"
    d
)

func main(){
    fmt.Println(a, b, c, d) // 1 1 one one
}

Однако, что толку от одинаковых констант? Настоящий полезный инструмент - генератор констант iota.

package main

import "fmt"

const (
	Sunday = iota
	Monday
	Wednesday
	Tuesday
	Thursday
	Friday
	Saturday
)

func main(){
	fmt.Println(Sunday, Monday, Wednesday, Tuesday, Thursday, Friday, Saturday)
}
//Результат:
//0, 1, 2, 3, 4, 5, 6

iota - на самом деле весьма мощный инструмент, в применении которого можно долго оттачивать своё искусство и проявлять изобретательность.

package main

import "fmt"

const (
	Zero = 1 << iota
	One
	Two
	Three
	Four
	Five
	Six
	Seven
	Eight
	Nine
	Ten
)

func main(){
	fmt.Println(Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten)
}
//Результат - таблица степеней двойки
//1 2 4 8 16 32 64 128 256 512 1024

Особенности констант в языке Go

Константы в языке Go являются выражениями, значение которых не может быть изменено в процессе выполнения программы. Это значение заранее известно компилятору, и вычисление его относится ко времени компиляции а не ко времени выполнения. Значения констант ограничиваются базовыми типами, а также именованными типами, производными от базовых. Внимательный читатель мог заметить, что при инициализации констант мы до сих пор ни разу не указывали явно тип, выводя его из присваиваемого значения. На самом же деле тип можно указывать явно, однако необходимо отметить, что в языке Go это делают нечасто, и это связано с определённой своеобразностью констант этом языке. Константы, объявленные без явного указания типа становятся нетипизированными. Числовые нетипизированные константы компилятор не привязывает к определённому типу, и они обрабатываются с повышенной точностью, и, таким образом, могут содержать в себе значения, превышающие разрядность базовых типов. Присвоение константе значения обычной переменной компилятором не допускается. При выполнении операций с константами, при необходимости, следует выполнять привидение типов. Проиллюстрируем сказанное примерами. Как и ранее, примеры местами будут содержать некоторые новые сущности и понятия, во избежание излишнего упрощения. Разумеется, значение всех действий объясняется в комментариях.

Объявление константы с явным указанием типа

package main

import "fmt"

//тип константы можно указать явно
const Pi float32 = 3.14

func main() {
	fmt.Println(Pi)
	fmt.Printf("%T", Pi) //узнать тип константы 
}
//Результат:
//3.14
//float32

Объявление константы именованного типа, производного от базового

package main

import "fmt"

//именованный тип T, производный от базового
type T int

const C T = 5


func main() {
	fmt.Println(C)
	fmt.Printf("%T", C) //узнать тип константы 
}
//Результат (ошибки нет):
//5
//main.T

А такие приёмы недопустимы

package main

import "fmt"

//именованный тип T, НЕ производный от базового
type T struct {
	a, b int
}

const C T = T{1, 1}

var i int = 5

const C1 = i

//Результат (ошибки):
//const initializer T literal is not a constant
//const initializer i is not a constant

Использование нетипизированных констант (полезнейшая вещь!)

package main

import "fmt"

//Константы: количество бит в пебибайте и эксбибайте
const pebi = 1125899906842624
const exbi = 1152921504606846976

func main() {
	fmt.Println(exbi/pebi) //математическая операция с операндами,
	//превышающими разрядность 64 bit!
	fmt.Printf("%T", exbi) //узнать тип константы
}
//Результат:
//1024
//constant 1152921504606846976 overflows int

Ещё один пример

package main

import "fmt"

//Количество метров в световом году (превышает 64 bit!)
const metersInLightYear = 9454254955488000

//Количество секунд в году
const secInYear = 31536000

func main() {
	//Вычислим скорость света в м/с
	var c = metersInLightYear / secInYear
	fmt.Println(c)
	
}
//Результат:
//299792458

Приведение типов

package main

import "fmt"

//Число Pi
const Pi = 3.14

//Радиус
var radius byte = 0x03

func main() {
	//Вычислим длину окружности
	fmt.Println(2 * Pi * radius)          // Ошибка!
	fmt.Println(2 * Pi * float64(radius)) //Нужно приведение типов!
	fmt.Printf("%T", Pi)                  //узнать тип константы
}
//Результат(нужно приведение типов):
//constant 6.28 truncated to integer 
//18.84
//float64

Пожалуй, теперь мы неплохо подготовлены и осведомлены в важной теме - использование констант в языке Go. "С чувством глубокого удовлетворения" двигаемся далее!

Last updated

Was this helpful?