Какие типы являются изменяемыми и неизменными на Google Go Language?
В Google Go я читал, что строки неизменяемы, нормально, но это int?
Как насчет других типов? Как немного более старый программист, я предпочитаю изменчивость, хотя я знаю преимущества неизменности, я предпочитаю жить опасно.
Знайте, какие типы являются изменяемыми или неизменяемыми, будут очень полезны.
Обновление, в чем меня больше всего беспокоят, - это практические проблемы в зависимости от того, какой тип является изменяемым или неизменным. Как и в типичном примере Java, если вы создаете String в цикле и цикле в 10 000 раз, вы получите 10000 строк, которые затем будут собраны в мусор. Это действительно было серьезной проблемой в проекте в компании, в которой я работал.
Возникает вопрос: неустойчивость Go в некоторых случаях вызывает ту же проблему?
Это влияет на то, как вы должны лечить var. (или я предполагаю, что это так).
Обновление снова, меня также беспокоят другие практические проблемы. Знание того, что что-то является неизменным, означает, что я могу писать код, который является параллельным, и обновление одной ссылки объекта не должно обновлять другие ссылки. Однако иногда я хочу делать опасные вещи, я хочу изменчивость.
Это последствия изменчивости против неизменности и влияют на то, как я могу написать код.
Ответы
Ответ 1
Не волнуйся - Иди, позволь тебе стрелять в ногу, если ты действительно хочешь: -)
Go не похож на Erlang, и это может быть то, с чем вы сталкиваетесь с вопросом.
x := 1
x = 2
выделяет одну переменную x
со значением 1
, затем переназначает ее на 2
- здесь не выделяется дополнительная память.
Как вы заметили, строки неизменяемы, поэтому выполнение строковых манипуляций может привести к созданию копий. Если вы обнаружите, что хотите сделать на месте изменения персональных данных, вы, вероятно, захотите использовать переменные []byte
через пакет bytes
.
Сообщение Russ Cox об этом должно ответить на большинство ваших вопросов об основных структурах данных: http://research.swtch.com/2009/11/go-data-structures.html
Как отмечали другие комментаторы, вам нужно посмотреть на семантику значений функций Go - они могут быть немного удивлены вначале.
Если у вас есть следующая функция:
func (t MyType) myFunc() {
// do something to set a field in t
}
и вы вызываете в своем коде
myVar.myFunc()
вы можете быть удивлены, увидев, что это не делает то, что вы хотите, потому что t
, который отображается в myFunc()
, действительно является копией myVar
.
Но будет работать следующее:
func (t *myType) myFunc() {
// do something to set a field in t
}
потому что функция имеет копию указателя и может получить доступ к базовой структуре с помощью этого указателя.
Ответ 2
По моему мнению, сначала следует выделить следующие два понятия:
Тогда ответ: Целочисленные переменные являются изменяемыми, целые значения неизменяемы.
Это представление согласуется с спецификацией Go, которая гласит, что строки неизменяемы. Очевидно, что строковая переменная изменена.
Переменные (как понятие) в Go не менее:
- названные переменные (такие как:
var i int
)
- переменные, доступные через указатели
Объекты Mutable Go:
- массивы и фрагменты
- карты
- Каналы
- которые захватывают по крайней мере 1 переменную из внешней области
Неизменяемые объекты Go:
- интерфейсы
- booleans, числовые значения (включая значения типа
int
)
- строки
- Указатели
- указатели на функции и замыкания, которые могут быть сведены к указателям на функции
- структуры, имеющие одно поле
Объекты Go, которые некоторые люди могут считать изменчивыми, в то время как другие люди могут считать их неизменяемыми:
- структуры, имеющие несколько полей
Ответ 3
Да, слово immutable появляется ровно один раз в Go spec. И это при обсуждении type string
. Я думаю, вы должны смотреть на это больше из точек двойного просмотра Assignability и Адресуемость. Например, Go запретит вам переписывать переменную на другое значение типа с невыложенными свойствами, очевидно. Как и в С++ для классов, не предоставляющих конструктор копирования, но в Go Pimpl чувствует себя намного менее неудобно, подобает сообществу goroutines путем общения с философией.
Ответ 4
"Мутируемость" имеет смысл только тогда, когда вы говорите о каком-то сложном типе, что имеет "внутренние" части, которые, возможно, могут быть изменены независимо от того, что его содержит. Строки, естественно, состоят из символов, и на языке нет механизма, который позволяет нам изменять символ в существующей строке, не дописывая целую новую строку, поэтому мы говорим, что она неизменна.
Для int нет смысла говорить о изменчивости, потому что, что такое "компоненты" int? Вы меняете int путем назначения целого нового int, но присваивание не считается "мутированием".
Существует некоторая связь между проблемами изменчивости и ссылочными или ценностными типами. Семантически, нет никакой разницы между неизменяемым ссылочным типом и типом значения. Зачем? Предположим, что int фактически был указателем на неизменяемый объект (т.е. *InternalIntObject
без функций для изменения InternalIntObject
). Когда вы назначаете такой указатель на переменную, он навсегда будет представлять одно и то же целочисленное значение (не может быть изменено другими, которые используют один и тот же объект), поскольку объект является неизменным. Это то же поведение, что и целочисленный тип значения. Вы можете назначить ints оператором присваивания; Аналогичным образом вы можете назначить эти указатели по заданию; результат будет таким же: назначенная переменная представляет то же самое целое число, что и назначенная. Единственным отличием было бы сравнение, и операторы арифметики должны были бы быть переопределены для удаления ссылки на указатель для вычисления результата.
Таким образом, взаимная совместимость имеет смысл только для ссылочных типов.
В соответствии с тем, что вы просили, "изменяемые" типы обычно считаются ссылочными типами, кроме строки: карты, каналы, срезы (по отношению к данным, указанным срезом), а также указатели на что угодно (поскольку вы можете изменить значение в месте, на которое указывает указатель).
Ответ 5
Ваше беспокойство, похоже, больше связано с распределением, чем с неизменностью. Неизменность, безусловно, влияет на распределение, делая невозможным повторное использование памяти. Умный компилятор, возможно, может повторно использовать любую "неизменную" память, чей адрес, который он знает, не исчезает.
Помимо строк, будьте осторожны с интерфейсами. При назначении на интерфейс (при оптимизации в сторону) должно быть выделено больше размера слова. Кроме того, переменные, объявленные в теле цикла, чьи адреса удаляются, в том числе через замыкание, должны будут выделяться каждый раз через цикл. В противном случае назначение - это просто назначение. Значение просто копируется в память, представленную переменной.
Если вы используете make или new в цикле или любой литерал, который создает ссылку, распределение должно произойти (опять же, при оптимизации).
В принципе, все сводится к попытке повторного использования памяти, где вы можете, и надеяться, что компилятор сделает это за вас, когда вы не сможете, если это имеет смысл сделать это.
Ответ 6
Это дает мне один и тот же адрес каждый раз, поэтому, возможно, ints изменяемы.
package main
import "fmt"
func main() {
var i int
i = 5
fmt.Println(&i)
i = 6
fmt.Println(&i)
var k = 7
i = k
fmt.Println(&i)
}