Go in a nutshell
  • Go in a nutshell
  • Введение
  • Родословная или Should I Go?
  • Hello, world!
  • Базовые типы данных
  • Go - установка, сборка
  • Алфавит и пакеты
  • Синтаксис
  • Приведение типов
  • Операторы
  • Константы
  • Управление потоком
  • Массивы, срезы, отображения
  • Именованные типы и структуры
  • Указатели и оператор new
  • Функции
  • Работа с параметрами командной строки
  • Завершение работы программы
  • Методы
Powered by GitBook
On this page
  • BOOL
  • STRING
  • Hex to ASCII text conversion table
  • Целочисленные типы
  • Вещественные числа
  • math/big
  • Комплексные числа

Was this helpful?

Базовые типы данных

Сейчас мы их проверим, сейчас мы их сравним...

Врага нужно знать в лицо. Этим безотлагательно и займёмся.

В первую очередь нам следует запомнить, что Go является компилируемым языком со строгой типизацией. С этой позиции и будем двигаться дальше. Все счастливые семьи похожи друг на друга. Несмотря на то, что во всех языках база - это плюс-минус одинаково, в Go есть свои нюансы, которые надо знать.

В текущей реализации языка я насчитал 19 базовых типов данных, включая алиасы:

bool

string

int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr

byte // алиас для uint8

rune // алиас для int32, представляет номер данного Unicode символа (специфический для Go тип, зато тип char отсутствует)

float32 float64

complex64 complex128

BOOL

Булев тип предсказуемо занимает 1 байт. В Go этот тип переменных отличен тем, что, не привязан к числовым эквивалентам как, к примеру, в языке C, где таковые эквиваленты вовсе подменяют собой отсутствующий тип bool. То есть 0 автоматически не равен false, а значащее число - true. Более того, не поможет и явное приведение типов:

fmt.Println(bool(0))
//cannot convert 0 (type untyped number) to type bool

Однако логика предикатов ожидаемо работает, и математические выражения в булевом контексте могут трактоваться как значения бинарной true/false логики:

fmt.Println(2 > 1)
//true

STRING

Строковый тип идёт со встроенной поддержкой юникода и только юникода (UTF-8). Байтовые последовательности прочих кодировок при оказии приходится всегда конвертировать с целью читаемости. Как к примеру в C#, строка в Go представляет собою неизменяемую последовательность байтов. То есть она как бы и массив (да и вообще строки и байтовые массивы - это как корпускулярно-волновой дуализм), однако строго необходимо помнить, что вольности, подобные таковым, не допускаются компилятором:

var str = "henep"
fmt.Println(str[0])
// 104 (0x68 hex) - как видим, строка тут же стремится к первородному массиву []byte
fmt.Println(string(str[0]))
// вот теперь "h", без явного приведения типов никуда
str[0] = "s"
//cannot assign to str[0]

Как видите, компилятор не дал нам уподобиться Тилю Уленшпигелю и смешать "henep" и "senep" =)

К всякой строке может быть применена встроенная функция len, возвращающая длину подлежащего байтового массива, но никак не количество символов. Снова из-за строки выглядывают ослиные уши байтового массива, поскольку любой UTF-8 символ, не совпадающий с ASCII таблицей, потребует для своего выражения от 2 до 4 байтов. Достаточно взглянуть на богатство и разнообразие национальных языков и распространённых символов, которые вобрала в себя UTF.Кроме прочего, вы немало ошибётесь, если сведёте вопрос к символьно-байтовому дуализму. Ведь есть ещё таинственные руны! Так что, впереди нас ещё ожидает весьма увлекательное исследование строко-байто-рунного единения (трёхкваркового конфайнмента?) в трёх лицах и функций для освоения всего этого хозяйства. Это не сложно.

Как водится, строки подвержены конкатенации:

var str1, str2 = "Hello", "world!"
fmt.Println(str1 + " " + str2)

Поскольку параметром функции Println() пакета fmt является тип intarface (базовый для прочих, как object в C#), возможны конструкции с гетерогенными включениями:

fmt.Println("Завтра сыну исполнится", 10, "лет!")
// или даже как-то так:
fmt.Println("Time now is:",time.Now().Format(time.Kitchen))

Разумеется, в проект должны быть включены пакеты "fmt" и "time", объявлена функция main, что было опущено для краткости изложения.

Также существует понятие так называемого "raw string literal". По смыслу это соответствует строкам с символом @ в C# или тегу в HTML. Синтаксическим представляет собой косые кавычки ` `, те, что живут на букве "ё". Я часто использую такие литералы для интеграции в скомпилированный бинарник внешних ресурсов вроде картинок в формате base64.

Забегая вперёд, хочу продемонстрировать, какого рода в рамках "строко-байтового дуализма", возможны операции со строками:

package main

import (
	"fmt"
)

func main() {
	var str1, str2 = "Hello ", "world!"
	fmt.Println(string(append([]byte(str1), []byte(str2)...)))

}
//Hello world!

Вот такая, с позволения сказать , конкатенация. Если размыслить, для меня это как у физиков - выражают же массы частиц в энергетическом эквиваленте. Масса T кварка 173,2 ± 0,7 ГэВ, и ничего, все радуются. Синхрофазотрон и полчаса работы лобзиком =)

Хотел удержаться, и обуздать размах мысли в целях соблюдения святой лапидарности, но всё же приведу таблицу HEX dictionary:

Hex to ASCII text conversion table

Hexadecimal

Binary

ASCII Character

00

00000000

NUL

01

00000001

SOH

02

00000010

STX

03

00000011

ETX

04

00000100

EOT

05

00000101

ENQ

06

00000110

ACK

07

00000111

BEL

08

00001000

BS

09

00001001

HT

0A

00001010

LF

0B

00001011

VT

0C

00001100

FF

0D

00001101

CR

0E

00001110

SO

0F

00001111

SI

10

00010000

DLE

11

00010001

DC1

12

00010010

DC2

13

00010011

DC3

14

00010100

DC4

15

00010101

NAK

16

00010110

SYN

17

00010111

ETB

18

00011000

CAN

19

00011001

EM

1A

00011010

SUB

1B

00011011

ESC

1C

00011100

FS

1D

00011101

GS

1E

00011110

RS

1F

00011111

US

20

00100000

Space

21

00100001

!

22

00100010

"

23

00100011

#

24

00100100

$

25

00100101

%

26

00100110

&

27

00100111

'

28

00101000

(

29

00101001

)

2A

00101010

*

2B

00101011

+

2C

00101100

,

2D

00101101

-

2E

00101110

.

2F

00101111

/

30

00110000

0

31

00110001

1

32

00110010

2

33

00110011

3

34

00110100

4

35

00110101

5

36

00110110

6

37

00110111

7

38

00111000

8

39

00111001

9

3A

00111010

:

3B

00111011

;

3C

00111100

<

3D

00111101

=

3E

00111110

>

3F

00111111

?

40

01000000

@

41

01000001

A

42

01000010

B

43

01000011

C

44

01000100

D

45

01000101

E

46

01000110

F

47

01000111

G

48

01001000

H

49

01001001

I

4A

01001010

J

4B

01001011

K

4C

01001100

L

4D

01001101

M

4E

01001110

N

4F

01001111

O

50

01010000

P

51

01010001

Q

52

01010010

R

53

01010011

S

54

01010100

T

55

01010101

U

56

01010110

V

57

01010111

W

58

01011000

X

59

01011001

Y

5A

01011010

Z

5B

01011011

[

5C

01011100

\

5D

01011101

]

5E

01011110

^

5F

01011111

_

60

01100000

`

61

01100001

a

62

01100010

b

63

01100011

c

64

01100100

d

65

01100101

e

66

01100110

f

67

01100111

g

68

01101000

h

69

01101001

i

6A

01101010

j

6B

01101011

k

6C

01101100

l

6D

01101101

m

6E

01101110

n

6F

01101111

o

70

01110000

p

71

01110001

q

72

01110010

r

73

01110011

s

74

01110100

t

75

01110101

u

76

01110110

v

77

01110111

w

78

01111000

x

79

01111001

y

7A

01111010

z

7B

01111011

{

7C

01111100

|

7D

01111101

}

7E

01111110

~

7F

01111111

DEL

Целочисленные типы

Первое, что о них нужно понимать, так это то, что они подвержены переполнению, что свойственно далеко не всем языкам (тому же, Pascal). Как и положено, существует "простой" архитектурно зависимый int . За ним следуют целые числа со знаком фиксированного размера — int8, int16, int32, int64 с аналогичным размером 8, 16, 32, 64 бита соответственно. Для исчисления диапазона значений данных типов необходимо воспользоваться формулой: −2n−1 до 2n−1−1, где n — размер типа.

Также, присутствуют и аналогичные беззнаковые типы - "обобщённый" uint, а также uint8, uint16, uint32, uint64. Число в названии типа, как и в предыдущем случае, задаёт размер, но диапазон значений составляет от 0 до 2n−1.

Рискуя заглянуть далеко вперёд, сообщу о том, что для преодоления ограничения домена значений переменных, к примеру uint64, а также осуществления операций с большими числами может использоваться специальный пакет "math/big", а также некоторые хитрости с нетипизированными константами, чья арифметика обрабатывается с гораздо большей числовой точностью, чем значения фундаментальных типов. Подробнее об этом мы поговорим позже.

Вещественные числа

Здесь всё предсказуемо. Числа с плавающей точкой представлены двумя типами - float32 и float64 - соответственно с простой и двойной точностью. Их размер составляет ожидаемые 32 и 64 бита в реализация соответствует стандарту IEEE 754. Размерность данных типов (так же как и, впрочем, всех целочисленных) можно увидеть, используя пакет "math":

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(math.MaxFloat32)
	fmt.Println(math.MaxFloat64)
}
//3.4028234663852886e+38
//1.7976931348623157e+308

math/big

Появление этого пакета в стандартной библиотеке Go привело к обсуждению такой сущности как числовые типы с неограниченной точностью. Позже я покажу на развёрнутом примере декодирования аппаратной информации (CID) вендора SD карт работу с пакетом math/big, большими числами, и даже битовыми оперциями с ними.

Комплексные числа

Физики любят говорить кОмпплексные, математики произносят комплЕксные числа.... Оставим это дело для математиков. Я же для красоты приведу вам такой код:

package main

import (
	"fmt"
	"image"
	"image/color"
	. "image/png"
	"log"
	"math/cmplx"
	"net/http"
)

var resultImg *image.RGBA

func handler(w http.ResponseWriter, r *http.Request) {
	f := Encode(w, resultImg)
	fmt.Fprintf(w, "%s", f)
}

func newton(z complex128) color.Color {
	const iterations = 37
	const contrast = 7
	for i := uint8(0); i < iterations; i++ {
		z -= (z - 1/(z*z*z)) / 4
		if cmplx.Abs(z*z*z*z-1) < 1e-6 {
			return color.Gray{255 - contrast*i}
		}
	}
	return color.Black
}

func main() {
	const (
		xmin, ymin, xmax, ymax = -2, -2, +2, +2
		width, height          = 1024, 1024
	)

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	for py := 0; py < height; py++ {
		y := float64(py)/height*(ymax-ymin) + ymin
		for px := 0; px < width; px++ {
			x := float64(px)/width*(xmax-xmin) + xmin
			z := complex(x, y)
			// Image point (px, py) represents complex value z.
			img.Set(px, py, newton(z))
		}
	}

	resultImg = img

	http.HandleFunc("/", handler)

	log.Println("Socket waiting connection on * : 3000")
	log.Fatal(http.ListenAndServe(":3000", nil))

}

Скомпилировав и запустив его, зайдите в любом браузере на страницу http://localhost:3000 и получите эстетическое наслаждение. То самое, которое несёт математика в своей стройности. Ах да, я же совсем забыл рассказать о сборке программ и установке нужных для этого компонентов! Что ж, исправляюсь!

PreviousHello, world!NextGo - установка, сборка

Last updated 4 years ago

Was this helpful?