← Назад к вопросам

Что произойдёт со слайсом после использования функции sort.Slice?

1.7 Middle🔥 61 комментариев
#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Влияние функции sort.Slice на слайс

Функция sort.Slice из пакета sort выполняет сортировку слайса "на месте" (in-place), то есть она модифицирует исходный слайс, а не возвращает новый. После её вывода исходный порядок элементов будет изменён согласно заданной функции сравнения.

Ключевые аспекты работы sort.Slice

  1. Изменение исходного слайса: Слайс в Go — это структура данных, содержащая указатель на массив, длину и ёмкость. sort.Slice работает непосредственно с этим массивом, переставляя элементы внутри него.

  2. Использование интерфейса sort.Interface: Внутри sort.Slice создаёт адаптер, который реализует sort.Interface (методы Len, Less, Swap), используя переданный слайс и функцию сравнения.

  3. Алгоритм сортировки: Начиная с Go 1.19, используется интроспективная сортировка (Introsort) — гибридный алгоритм, сочетающий быструю сортировку, пирамидальную сортировку и сортировку вставками. Это гарантирует производительность O(n log n) в худшем случае.

Пример и демонстрация

Рассмотрим практический пример:

package main

import (
    "fmt"
    "sort"
)

func main() {
    // Исходный слайс
    numbers := []int{5, 2, 9, 1, 5, 6}
    fmt.Println("До сортировки:", numbers) // [5 2 9 1 5 6]
    
    // Сортировка по возрастанию
    sort.Slice(numbers, func(i, j int) bool {
        return numbers[i] < numbers[j]
    })
    
    fmt.Println("После сортировки:", numbers) // [1 2 5 5 6 9]
    
    // Сортировка по убыванию
    sort.Slice(numbers, func(i, j int) bool {
        return numbers[i] > numbers[j]
    })
    
    fmt.Println("Обратная сортировка:", numbers) // [9 6 5 5 2 1]
}

Важные технические детали

  • Стабильность: sort.Slice не является стабильной сортировкой — равные элементы могут изменить свой относительный порядок. Для стабильной сортировки используйте sort.SliceStable.

  • Влияние на другие ссылки: Поскольку слайс — это ссылочный тип, все переменные, указывающие на тот же базовый массив, увидят изменения:

a := []int{3, 1, 2}
b := a  // b ссылается на тот же массив, что и a

sort.Slice(a, func(i, j int) bool { return a[i] < a[j] })
fmt.Println(b) // [1 2 3] — b также отсортирован!
  • Безопасность при параллельном доступе: sort.Slice не является потокобезопасной. Если несколько горутин обращаются к слайсу во время сортировки, требуется синхронизация.

  • Работа с разными типами: sort.Slice работает с любым типом слайса благодаря использованию reflect внутри, но это накладывает небольшие накладные расходы по сравнению с типизированными функциями вроде sort.Ints.

Сравнение с другими функциями сортировки

ФункцияИзменяет исходный слайсСтабильностьПроизводительностьТипизация
sort.SliceДаНетO(n log n)Обобщённая
sort.SliceStableДаДаO(n log n)Обобщённая
sort.IntsДаНетO(n log n)Типизированная
sorted := slices.Sort(slice)Зависит от реализацииЗависитO(n log n)Обобщённая

Рекомендации по использованию

  1. Для простых типов используйте специализированные функции (sort.Ints, sort.Strings) — они быстрее и читабельнее.

  2. Если важен порядок равных элементов — выбирайте sort.SliceStable.

  3. Проверяйте функцию сравнения на корректность — она должна быть строгой и транзитивной, иначе возможны паники или неопределённое поведение.

  4. Учитывайте, что сортировка изменяет оригинал — при необходимости сохраняйте исходные данные:

original := []int{3, 1, 2}
sorted := make([]int, len(original))
copy(sorted, original)
sort.Ints(sorted)

Заключение

После вызова sort.Slice исходный слайс будет необратимо изменён — его элементы переупорядочены согласно функции сравнения. Это эффективная операция, не требующая дополнительной памяти (кроме стека вызовов), но важно помнить о её побочных эффектах, особенно при наличии нескольких ссылок на один массив. Для большинства случаев использования sort.Slice предоставляет оптимальный баланс между гибкостью и производительностью.