Задачи на строки

1) Что выведет данная программа и почему?

package main
import "fmt"

func main() {

	s0 := "some string"
	s1 := []byte(s0)
	
	s2 := s1[5:]
	
	s2[3] = 'o'
	
	fmt.Println(string(s2))
	fmt.Println(string(s1))
	fmt.Println(string(s0))

}

Давайте разберем, что происходит в данной программе на GoLang шаг за шагом:

  1. s0 := "some string" - создается строка s0 со значением "some string".

  2. s1 := []byte(s0) - строка s0 преобразуется в слайс байтов s1. Теперь s1 содержит байты, соответствующие каждому символу строки "some string".

  3. s2 := s1[5:] - создается слайс s2, который является срезом s1, начиная с 6-го элемента (индексация начинается с 0). Таким образом, s2 будет содержать байты, начиная с символа 's' в слове "string".

  4. s2[3] = 'o' - четвертый элемент (индекс 3) слайса s2 изменяется на байт, соответствующий символу 'o'. Поскольку s2 ссылается на те же данные, что и s1, изменение s2 также изменяет s1. В исходной строке "string" буква 'i' (четвертый символ) заменяется на 'o', получается "strong".

Теперь рассмотрим вывод каждой из строк:

  • fmt.Println(string(s2)) - выводит преобразованный s2, т.е. "strong".

  • fmt.Println(string(s1)) - выводит преобразованный s1, т.е. "some strong", так как изменения в s2 затронули и s1.

  • fmt.Println(string(s0)) - выводит исходную строку s0, которая не изменилась и остается "some string", так как строки в Go иммутабельны и изменения в байтовом слайсе не влияют на исходную строку.

Итак, вывод программы будет следующим:

strong
some strong
some string

2) Что выведет программа? Как исправить?

package main
	
func main() {	
	s := "test"
	println(s[0])
	s[0]="R"
	println(s)
}

Давайте разберем, что произойдет при выполнении этой программы и как ее можно исправить.

Разбор кода

  1. Создание строки s:

    s := "test"

    Здесь создается строка s со значением "test".

  2. Вывод первого символа строки:

    println(s[0])

    s[0] возвращает первый байт строки s, который соответствует символу 't'. В Go строки являются неизменяемыми последовательностями байтов, поэтому s[0] вернет байт, соответствующий символу 't', что равно 116 в ASCII.

  3. Попытка изменения первого символа строки:

    s[0] = 'R'

    Здесь программа пытается изменить первый символ строки s на 'R'. Однако строки в Go неизменяемы, и попытка изменить их напрямую приведет к ошибке компиляции:

    cannot assign to s[0]

Исправление программы

Чтобы изменить строку в Go, нужно создать новую строку с необходимыми изменениями. Один из способов сделать это — преобразовать строку в срез байтов, изменить нужный байт, а затем преобразовать срез байтов обратно в строку.

Исправленный код

package main

import "fmt"

func main() {	
	s := "test"
	fmt.Println(s[0]) // Выводит 116, что соответствует 't' в ASCII

	// Преобразуем строку в срез байтов
	b := []byte(s)
	b[0] = 'R'

	// Преобразуем срез байтов обратно в строку
	s = string(b)
	fmt.Println(s) // Выводит "Rest"
}

Вывод исправленной программы

Исправленная программа выведет:

116
Rest

Объяснение исправленного кода

  1. Преобразование строки в срез байтов:

    b := []byte(s)

    Это позволяет изменять отдельные байты строки.

  2. Изменение первого байта:

    b[0] = 'R'

    Здесь первый байт изменяется на 'R'.

  3. Преобразование среза байтов обратно в строку:

    s = string(b)

    Это создает новую строку с измененным содержимым.

Таким образом, исправленный код корректно изменяет первый символ строки и выводит ожидаемый результат. Однако этот код будет работать некоррекно сo строками, содержащими символы, представленные несколькими байтами (например, кириллица или другие символы Unicode), может привести к некорректным результатам. В таких случаях лучше использовать срезы рун (rune), так как руны представляют собой символы Unicode и могут корректно обрабатывать многобайтовые символы.

Исправленный код с использованием рун

package main

import "fmt"

func main() {	
	s := "тест"
	
	// Преобразуем строку в срез рун
	r := []rune(s)

	fmt.Println(string(r[0])) // Выводит первый символ строки, что соответствует 'т'
	r[0] = 'Р'

	// Преобразуем срез рун обратно в строку
	s = string(r)
	fmt.Println(s) // Выводит "Рест"
}

Объяснение исправленного кода

  1. Преобразование строки в срез рун:

    r := []rune(s)

    Это позволяет работать с символами Unicode, включая многобайтовые символы.

  2. Изменение первого символа:

    r[0] = 'Р'

    Здесь первый символ изменяется на 'Р'.

  3. Преобразование среза рун обратно в строку:

    s = string(r)

    Это создает новую строку с измененным содержимым.

Вывод исправленной программы

Исправленная программа выведет:

т
Рест

Заключение

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

Last updated