Меня часто спрашивают, почему указатели лучше? Шёрт побери, вот почему!

Описание функций меняющих местами значения переменных:

1. Функция с указателями:

func swapValues(first, second *int) {
    fmt.Println("Перед:", *first, *second)
    temp := *first
    *first = *second
    *second = temp
    fmt.Println("После:", *first, *second)
}

Эта функция использует указатели на целые числа (*int). При вызове функции передаются адреса переменных, что позволяет функции изменять реальные значения переменных в вызывающей среде. Это называется передачей по ссылке.

2. Функция с передачей значений:

func swapValues(first, second int) {
    fmt.Println("Перед:", first, second)
    temp := first
    first = second
    second = temp
    fmt.Println("После:", first, second)
}

Эта функция принимает копии значений first и second (типа int). Она работает с этими копиями локально, что означает, что оригинальные значения в вызывающей среде остаются неизменными. Это называется передачей по значению.

Сравнение аспектов:

Аспект

Первая функция (с указателями)

Вторая функция (с передачей значений)

Передача параметров

+

-

Использование памяти

+

-

Изменение данных вызвавшей стороны

+

-

Накладные расходы на разыменование

-

+

Накладные расходы на копирование

+

-

Производительность

+

-

Случай использования

+

-

Эффективность работы с кэшом

+

-

Подходит для больших данных

+

-

Влияние на оригинальные значения

+

-

Итого

8+

2+

Подробности по каждому аспекту:

  1. Передача параметров:

    • Первая функция использует указатели, что позволяет изменять оригинальные значения в вызывающей функции (передача по ссылке).

    • Вторая функция работает с копиями значений и не изменяет исходные данные (передача по значению).

  2. Использование памяти:

    • Первая функция передаёт указатели, которые занимают меньше памяти (4 или 8 байт), поэтому она использует меньше памяти.

    • Вторая функция создаёт копии значений, что приводит к большему расходу памяти, особенно для больших данных.

  3. Изменение данных вызвавшей стороны:

    • Первая функция изменяет оригинальные значения в вызывающей среде.

    • Вторая функция изменяет только локальные копии значений.

  4. Накладные расходы на разыменование:

    • Первая функция использует разыменование указателей, что добавляет небольшие накладные расходы.

    • Вторая функция работает напрямую с копиями значений, что делает доступ к данным немного быстрее.

  5. Накладные расходы на копирование:

    • Первая функция не копирует данные, передавая только указатели.

    • Вторая функция создаёт копии значений, что может быть накладно для больших данных.

  6. Производительность:

    • Первая функция быстрее для больших данных, так как она избегает копирования.

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

  7. Случай использования:

    • Первая функция лучше подходит, когда нужно изменить исходные данные.

    • Вторая функция полезна, если требуется работать с копиями данных без изменения оригинала.

  8. Эффективность работы с кэшом:

    • Первая функция более эффективна при работе с большими данными, так как изменяет данные на месте, без создания копий.

    • Вторая функция менее эффективна, так как работает с копиями данных.

  9. Подходит для больших данных:

    • Первая функция эффективнее для работы с большими структурами данных или массивами, так как не требует копирования.

    • Вторая функция менее эффективна, так как создаёт копии данных.

  10. Влияние на оригинальные значения:

    • Первая функция изменяет оригинальные значения, что полезно в случаях, когда это необходимо.

    • Вторая функция не влияет на оригинальные значения, так как работает с копиями.

Итоговое сравнение:

Аспект

Первая функция (с указателями)

Вторая функция (с передачей значений)

Итого

8+

2+

Первая функция выигрывает в 8 аспектах, а вторая — в 2 аспектах.


Заключение:

Первая функция (с указателями) в 4 раза лучше по общим параметрам, чем вторая функция (с передачей значений).

Ну вот и все! Ж:-)

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


  1. Posya
    23.10.2024 07:55

    Чем яблоко лучше автомобиля:

    1. Оно легче помещается в карман

    2. Оно слаще

    3. ....

    PROFIT!


  1. evgeniy_kudinov
    23.10.2024 07:55

    Где пруфы, Билли? Нам нужны пруфы


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


    1. Sly_tom_cat
      23.10.2024 07:55

      package main
      
      import (
      	"testing"
      )
      
      var (
      	a1 = 10
      	a2 = 20
      )
      
      func swapValuesP(first, second *int) (*int, *int) {
      	temp := *first
      	*first = *second
      	*second = temp
      	return first, second
      }
      
      func swapValuesV(first, second int) (int, int) {
      	temp := first
      	first = second
      	second = temp
      	return first, second
      }
      
      func BenchmarkSwapValuesP(b *testing.B) {
      	for range b.N {
      		swapValuesP(&a1, &a2)
      	}
      }
      
      func BenchmarkSwapValuesV(b *testing.B) {
      	for range b.N {
      		swapValuesV(a1, a2)
      	}
      }
      
      goos: linux
      goarch: amd64
      pkg: pointer_vs_copy
      cpu: AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx
      BenchmarkSwapValuesP
      BenchmarkSwapValuesP-8      400667139            2.948 ns/op           0 B/op          0 allocs/op
      BenchmarkSwapValuesV
      BenchmarkSwapValuesV-8      1000000000           0.4211 ns/op          0 B/op          0 allocs/op
      PASS
      ok      pointer_vs_copy 1.990s

      NO COMMENTS


      1. kravlad
        23.10.2024 07:55

        В статье и написано, что инты эффективнее по значению передавать. Что вы хотели этим бенчмарком показать?


  1. RodionGork
    23.10.2024 07:55

    вот это тема, вот это открытие :)

    попробуйте мьютекс или waitgroup передать в функцию по указателю и без. можно получить удивительнейшие результаты.


  1. ShaggyCat2
    23.10.2024 07:55

    Хотелось бы увидеть юзкейсы, где лучше применять функции с указателем или без и какие будут плюсы-минусы. Без юзкейсов всё это слишком неопределенно.


  1. serjeant
    23.10.2024 07:55

    Очень странно, почему вы не использовали синтаксис go для обмена значениями переменных:
    first,second = second,first

    *first,*second = *second,*first, кстати прежде чем разыменовывать указатели, было бы неплохо их на nil проверить.