Какие типы являются изменяемыми и неизменными в Google Go Language? - PullRequest
31 голосов
/ 05 ноября 2011

В Google Go я прочитал, что строки неизменяемы, хорошо, но int?А как насчет других типов?Как программист немного старше, я предпочитаю изменчивость, хотя я знаю преимущества неизменяемости, я предпочитаю жить опасно.

Знать, какие типы являются изменяемыми или неизменяемыми, было бы очень полезно.


Обновление, что меня больше всего беспокоит, так это практические проблемы, зависящие от типа изменяемого или неизменяемого типа.Как и в типичном примере в Java, если вы создадите String в цикле и цикле 10 000 раз, вы получите 10 000 созданных String, которые затем будут собираться мусором.На самом деле это было серьезной проблемой в проекте компании, в которой я работал.

Вопрос в том, вызывает ли неизменность Go в некоторых случаях ту же проблему?

Это влияет на то, как вы должны относиться к вар.(или я предполагаю, что это так).


Обновите еще раз, я также обеспокоен другими практическими проблемами.Знание того, что что-то является неизменным, означает, что я могу писать код, который является параллельным, и обновления одной ссылки на объект не должны обновлять другие ссылки.Однако иногда я хочу делать опасные вещи, я хочу изменчивость.

Это последствия изменчивости против неизменности и влияют на то, как я могу написать код.

Ответы [ 6 ]

32 голосов
/ 05 ноября 2011

Не волнуйтесь - Го позволит вам выстрелить себе в ногу, если вы действительно хотите: -)

Го не похож на Эрланга, что может быть тем, к чему вы стремитесь с вопросом.

x := 1
x = 2

выделяет одну переменную x со значением 1, затем переназначает ее на 2 - здесь не выделяется дополнительная память.

Как вы заметили, строки являются неизменяемыми, поэтому выполнение манипуляции со строками может привести к созданию копий.Если вы обнаружите, что хотите внести изменения в символьные данные на месте, вы, вероятно, захотите работать с переменными []byte с помощью пакета bytes.

Пост Расса Кокса об этом должен ответить больше всего.из ваших вопросов об основных структурах данных: 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
}

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

10 голосов
/ 05 ноября 2011

По моему мнению, сначала следует выделить следующие два понятия:

  • целые числа как математические объекты (то есть: значения)

  • переменные типа int

Тогда ответ таков: Целочисленные переменные являются изменяемыми, целочисленные значения неизменны.

Это представление согласуется сспецификация Go, в которой говорится, что строки неизменны.Очевидно, что строка переменная является изменяемой.

Переменные (как концепция) в Go имеют как минимум:

  • именованных переменных (таких как: var i int)
  • переменные доступны через указатели

Изменяемые объекты Go:

  • массивы и фрагменты
  • карты
  • каналов
  • замыкания, которые захватывают как минимум 1 переменную из внешней области видимости

Неизменяемые объекты Go:

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

объекты Go, которые некоторые люди могут считать изменяемыми, в то время как другие могут считать их неизменяемыми:

  • структуры, имеющие несколько полей
2 голосов
/ 05 ноября 2011

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

Для int не имеет смысла говорить об изменчивости, потому что, каковы "компоненты" int? Вы изменяете int, назначая совершенно новый int, но назначение не считается "мутирующим".

Существует некоторая связь между проблемами изменчивости и ссылочных типов. Семантически нет никакой разницы между неизменным ссылочным типом и типом значения. Зачем? Предположим, что int на самом деле был указателем на неизменяемый объект (т.е. *InternalIntObject без функций для изменения InternalIntObject). Как только вы назначите такой указатель на переменную, он всегда будет представлять одно и то же целочисленное значение (не может быть изменено другими, которые совместно используют один и тот же объект), поскольку объект является неизменным. Это то же самое поведение, что и тип целочисленного значения. Вы можете назначить целые числа оператором присваивания; также вы можете назначить эти указатели по назначению; результат будет таким же: назначенная переменная представляет собой то же целое число, что и то, чему она была назначена. Единственным отличием будет сравнение, и арифметические операторы придется переопределять, чтобы отменить ссылку на указатель для вычисления результата.

Поэтому изменчивость имеет смысл только для ссылочных типов.

Что касается того, что вы просили, то «изменяемые» типы обычно считаются ссылочными типами, кроме строки: карты, каналы, срезы (относительно данных, на которые указывает срез), а также указатели на что-либо (так как Вы можете изменить значение в месте, указанном указателем).

2 голосов
/ 05 ноября 2011

Да, слово неизменный встречается ровно один раз в спецификации Go.И это при обсуждении type string.Я думаю, вам стоит взглянуть на это с точки зрения двойного подхода: Назначаемость и Адресность .Например, Go запретит вам связывать переменную с другим значением типа с неэкспортированными свойствами, очевидно.В некотором роде, как в C ++ для классов, не предоставляющих конструктор копирования, но в Go Pimpl чувствует себя гораздо менее неловко, приличествуя общему согласию goroutines , сообщая философию .*

1 голос
/ 06 ноября 2011

Похоже, ваша забота больше связана с распределением, а не с неизменностью.Неизменность, безусловно, влияет на распределение, делая невозможным повторное использование памяти.Умный компилятор может повторно использовать любую «неизменяемую» память, адрес которой он не знает.

Помимо строк, будьте осторожны с интерфейсами.Все, что больше, чем размер слова, должно быть выделено при назначении интерфейсу (без оптимизации).Кроме того, переменные, объявленные в теле цикла, адреса которых экранируются, в том числе посредством замыкания, должны будут выделяться каждый раз через цикл.В противном случае, однако, назначение - это просто назначение.Значение просто копируется в память, представленную переменной.

Если вы используете make или new в цикле, или любой литерал, который создает ссылку, распределение должно произойти (опять же, при условии оптимизации).

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

0 голосов
/ 05 ноября 2011

Это дает мне один и тот же адрес каждый раз, поэтому возможно целые числа изменяемы.

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)
}
...