2016-04-19 3 views
1

Кто-нибудь может объяснить мне, почему адрес &c1.name такой же после того, как он был изменен в функции changeMe(). Я думал, что струны неизменны в Го.Неизменяемые строки в Go

package main 

import "fmt" 

type customer struct { 
    name string 
    age int 
} 

func main() { 
    c1 := customer{"Todd", 44} 
    fmt.Println(&c1.name) // 0x8201e4120 

    changeMe(&c1) 

    fmt.Println(c1)  // {Rocky 44} 
    fmt.Println(&c1.name) // 0x8201e4120 
} 

func changeMe(z *customer) { 
    fmt.Println(z)  // &{Todd 44} 
    fmt.Println(&z.name) // 0x8201e4120 
    z.name = "Rocky" 
    fmt.Println(z)  // &{Rocky 44} 
    fmt.Println(&z.name) // 0x8201e4120 
} 
+0

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

+0

да,' c1' не изменяется, но это поле 'имя 'неизменен, не так ли? Поэтому, когда я меняю имя, он должен иметь новый адрес. Что делать, если я хочу хранить экстремально большую строку, как компилятор хранит ее, когда она все еще использует тот же адрес? – camabeh

ответ

9

Неизменяемость строк - это не то же самое, что неизменяемость переменных.

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

Переменные в Go всегда изменяемы. При изменении строковой переменной внутренние поля переменной (указатель и длина) изменяются. Адрес переменной никогда не изменяется.

В приведенном ниже примере представлены внутренности строковой переменной Go. Первое целое число - это адрес массива символов, а второй - длина.

См. Статью о внутренних элементах строки в Go http://research.swtch.com/godata.

package main 

import (
     "fmt" 
     "reflect" 
     "unsafe" 
) 

func main() { 
    var x string = "abc" 
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x))) 
    x = "cde" 
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x))) 
    x = x[1:] 
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x))) 
} 

Playground

+2

В пакете отражения есть также [StringHeader] (https://golang.org/pkg/reflect/#StringHeader), который отражает фактический строковый структурный макет в [runtime/string.go] (https: // golang .org/src/runtime/string.go # L215) – JimB

+0

Спасибо. Все это имеет смысл сейчас. – camabeh

Смежные вопросы