#5.2 golang Строки: работа со string

Значение по умолчанию для строки — это пустая строка.
Строка объявляется в двойных кавычках, и при этом внутри этих двойных кавычек могут быть спецсимволы, такие как перенос строки либо символ табуляции.

// пустая строка по-умолчанию
var str string
// со спец символами
var hello string = "Привет!\n\tПривет2!"

Если же вы хотите писать "как есть", то есть чтобы даже спецсимволы выводились как обычный текст, то вы можете использовать обратные кавычки.

// без спец символов
var world string = `Привет!\n\tПривет2!`

Для сравнения можно запустить программу:

package main

import (
	"fmt"
)

func main() {
	var hello string = "Привет!\n\tПривет2!"
	var helloAsIs string = `Привет!\n\tПривет2!`
	fmt.Println("1) " + hello)
	fmt.Println("2) " + helloAsIs)
}

В терминале получим что-то вроде:

1) Привет!
	Привет2!
2) Привет!\n\tПривет2!

UTF-8 для строк "из коробки"

В go строки сразу, "из коробки" поддерживают UTF-8, поэтому вы можете там писать на практически любых алфавитах, в данном случае
на русском:

// UTF-8 доступен сразу из коробки
var helloWorld = "Привет, Мир!"

Одинарные кавычки в go используются для символов, которые объявляются с типом byte, который является по сути псевдонимом для uint8.

// одинарные кавычки для типа byte (uint8)
var rawBinary byte = '\x27'

Либо же для типа rune, который представляет собой полноценный UTF-8 символ (под капотом это uint32):

// Тип rune (uint32) для UTF-8 символов
var someRune rune = '*'

В go конечно же можно можно конкатенировать строки - а именно с помощью плюса:

helloWorld := "Привет Мир"
// конкатенация строк
andGoodMorning := helloWorld + " и доброе утро!"

При этом вы не можете заменить какой-то один символ строки, например так:

// Ошибка cannot assign to helloWorld[0]
helloWorld[0] = 72

- в данном случае получим ошибку, дело тут в том, что строки неизменяемы, при каждой операции со строкой происходит выделение памяти (аллокация) для новой строки.

Чтобы избежать дополнительных аллокаций, можно использовать Builder из пакета strings, например:

package main

import (
	"fmt"
	"strings"
)

func main() {
	var sb strings.Builder

	sb.WriteString("Привет")
	sb.WriteString(" ")
	sb.WriteString("Мир")

	str := sb.String()
	fmt.Println(str) // Hello world
}

Длина строки, подстроки, получение "символа"

Если вы попробуете получить длину строки, используя встроенную функцию len, то вы получите длину в байтах (а не в символах):

// получение длины строки
byteLen := len(helloWorld) // 19 байт

Часто в прикладных задачах нам нужно вовсе не это, ведь это не символы.

Если внутри строки данные в кодировке utf, то один символ может занимать больше одного байта.
Поэтому, если мы хотим получить именно количество символов, то можем использовать функцию RunCountInString из пакета utf8:

symbols := utf8.RuneCountInString(helloWorld) // 10 рун

Строки как срезы байт

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

Key Words for FKN + antitotal forum (CS VSU):