수색…


소개

구조체는 함께 묶인 다양한 변수의 집합입니다. 구조체 자체는 변수가 들어있는 패키지 일 뿐이며 쉽게 액세스 할 수 있습니다.

C와는 달리 Go 구조체는 메소드를 첨부 할 수 있습니다. 또한 인터페이스를 구현할 수 있습니다. Go의 구조체는 객체와 유사하지만 상속과 같은 객체 지향 언어로 알려진 주요 기능이 누락되어 있습니다.

기본 선언

기본 구조체는 다음과 같이 선언됩니다.

type User struct {
    FirstName, LastName string
    Email               string
    Age                 int
}

각 값을 필드라고합니다. 필드는 보통 한 줄에 하나씩 쓰여지며 그 필드의 이름은 그 유형보다 선행합니다. 위의 예제에서 FirstNameLastName 과 같은 유형의 연속 필드를 결합 할 수 있습니다.

공개되지 않은 필드와 비공개 필드 (비공개 대 공용)

이름이 대문자로 시작되는 구조 필드가 내보내집니다. 다른 모든 이름은 안보이게됩니다.

type Account struct {
    UserID      int    // exported
    accessToken string // unexported
}

비공개 필드는 동일한 패키지 내의 코드에서만 액세스 할 수 있습니다. 따라서 다른 패키지의 필드에 액세스하는 경우 이름은 대문자로 시작해야합니다.

package main

import "bank"

func main() {
    var x = &bank.Account{
        UserID: 1,          // this works fine
        accessToken: "one", // this does not work, since accessToken is unexported
    }
}

그러나 bank 패키지에서 UserId와 accessToken에 문제없이 액세스 할 수 있습니다.

패키지 bank 는 다음과 같이 구현 될 수 있습니다.

package bank

type Account struct {
    UserID int
    accessToken string
}

func ProcessUser(u *Account) {    
    u.accessToken = doSomething(u) // ProcessUser() can access u.accessToken because 
                                   // it's defined in the same package
}

합성 및 삽입

컴포지션은 상속에 대한 대안을 제공합니다. 구조체는 선언에 이름으로 다른 유형을 포함 할 수 있습니다.

type Request struct {
    Resource string
}

type AuthenticatedRequest struct {
    Request
    Username, Password string
}

위의 예제에서 AuthenticatedRequest 에는 네 개의 공개 멤버 인 Resource , Request , UsernamePassword 됩니다.

복합 구조체는 인스턴스화되어 일반 구조체와 같은 방식으로 사용될 수 있습니다.

func main() {
    ar := new(AuthenticatedRequest)
    ar.Resource = "example.com/request"
    ar.Username = "bob"
    ar.Password = "P@ssw0rd"
    fmt.Printf("%#v", ar)
}

놀이터에서 놀아 라.

퍼가기

앞의 예에서 Request 는 포함 된 필드입니다. 컴포지션은 다른 유형을 임베드하여 수행 할 수도 있습니다. 예를 들어, 더 많은 기능을 가진 Struct을 장식하는 데 유용합니다. 예를 들어, Resource 예제를 계속 진행하면서 Resource 필드의 내용을 http:// 또는 https:// 접두어로 형식화하는 함수가 필요합니다. 우리는 두 가지 옵션이 있습니다 : AuthenticatedRequest에 새로운 메소드를 생성하거나 다른 구조체로부터 그것을 삽입 하십시오 :

type ResourceFormatter struct {}

func(r *ResourceFormatter) FormatHTTP(resource string) string {
    return fmt.Sprintf("http://%s", resource)
}
func(r *ResourceFormatter) FormatHTTPS(resource string) string {
    return fmt.Sprintf("https://%s", resource)
}


type AuthenticatedRequest struct {
    Request
    Username, Password string
    ResourceFormatter
}

이제 주요 기능은 다음을 수행 할 수 있습니다.

func main() {
    ar := new(AuthenticatedRequest)
    ar.Resource = "www.example.com/request"
    ar.Username = "bob"
    ar.Password = "P@ssw0rd"

    println(ar.FormatHTTP(ar.Resource))
    println(ar.FormatHTTPS(ar.Resource))

    fmt.Printf("%#v", ar)
}

ResourceFormatter 내장 된 AuthenticatedRequest 가 있는지 확인하십시오.

그러나 단점은 컴포지션 외부의 개체에 액세스 할 수 없다는 것입니다. 따라서 ResourceFormatterAuthenticatedRequest 멤버에 액세스 할 수 없습니다.

놀이터에서 놀아 라.

행동 양식

구조체 메소드는 함수와 매우 유사합니다.

type User struct {
    name string
}

func (u User) Name() string {
    return u.name
}

func (u *User) SetName(newName string) {
    u.name = newName
}

유일한 차이점은 메서드 수신기가 추가 된 것입니다. 이것은 유형의 인스턴스 또는 유형의 인스턴스에 대한 포인터로 선언 될 수 있습니다. SetName() 은 인스턴스를 변경하기 때문에 수신자는 인스턴스에서 영구적 인 변경을 수행하기 위해 포인터 여야합니다.

예 :

package main

import "fmt"

type User struct {
    name string
}

func (u User) Name() string {
    return u.name
}

func (u *User) SetName(newName string) {
    u.name = newName
}

func main() {
    var me User

    me.SetName("Slim Shady")
    fmt.Println("My name is", me.Name())
}

운동장에 가라.

익명 구조체

익명 구조체를 생성하는 것이 가능합니다 :

data := struct {
    Number int 
    Text   string
} { 
    42, 
    "Hello world!",
}

전체 예제 :

package main

import (
    "fmt"
)

func main() {
    data := struct {Number int; Text string}{42, "Hello world!"} // anonymous struct
    fmt.Printf("%+v\n", data)
}

놀이터에서 놀아 라.

태그

구조체 필드에는 태그가 연결될 수 있습니다. 이러한 태그는 reflect 패키지에서 읽을 수 있으므로 개발자가 필드에 대해 지정한 사용자 정의 정보를 얻을 수 있습니다.

struct Account {
    Username      string `json:"username"`
    DisplayName   string `json:"display_name"`
    FavoriteColor string `json:"favorite_color,omitempty"`
}

위의 예에서 태그는 JSON을 마샬링하거나 언 마샬링 할 때 encoding/json 패키지에서 사용하는 키 이름을 변경하는 데 사용됩니다.

태그는 임의의 문자열 값이 될 수 있지만 공백으로 구분 된 key:"value" 쌍을 사용하는 것이 가장 좋습니다.

struct StructName {
    FieldName int `package1:"customdata,moredata" package2:"info"`
}

encoding/xmlencoding/json 패키지와 함께 사용되는 struct 태그는 표준 libarary에서 사용됩니다.

struct 복사본 만들기.

struct는 할당을 사용하여 간단히 복사 할 수 있습니다.

type T struct {
    I int
    S string
}

// initialize a struct
t := T{1, "one"}

// make struct copy
u := t // u has its field values equal to t

if u == t { // true
    fmt.Println("u and t are equal") // Prints: "u and t are equal"
}

위의 경우 't' 와 'u'는 이제 별도의 객체 (구조체 값)입니다.

T 는 필드로 참조 유형 (슬라이스, 맵, 채널)을 포함하지 않으므로 위의 tu 는 서로 영향을주지 않고 수정할 수 있습니다.

fmt.Printf("t.I = %d, u.I = %d\n", t.I, u.I) // t.I = 100, u.I = 1

그러나 T 에 참조 유형이 포함 된 경우 (예 :

type T struct {
    I  int
    S  string
    xs []int // a slice is a reference type
}

그런 다음 할당에 의한 간단한 복사가 슬라이스 유형 필드의 값을 새 객체에 복사합니다. 동일한 슬라이스 객체를 참조하는 두 개의 서로 다른 객체가 생성됩니다.

// initialize a struct
t := T{I: 1, S: "one", xs: []int{1, 2, 3}}

// make struct copy
u := t // u has its field values equal to t

u와 t가 모두 자신의 필드 xs를 통해 동일한 슬라이스를 참조하기 때문에 한 객체의 슬라이스에서 값을 업데이트하면 다른 객체의 슬라이스에 변경 사항이 반영됩니다.

// update a slice field in u
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 500 3], u.xs = [1 500 3]

따라서이 참조 유형 속성이 의도하지 않은 동작을 생성하지 않도록하려면주의해야합니다.

예를 들어 위의 객체를 복사하려면 슬라이스 필드의 명시적인 사본을 수행 할 수 있습니다.

// explicitly initialize u's slice field
u.xs = make([]int, len(t.xs))
// copy the slice values over from t
copy(u.xs, t.xs)

// updating slice value in u will not affect t
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 2 3], u.xs = [1 500 3]

구조체 리터럴

struct 유형의 값은 해당 필드의 값을 지정하는 struct 리터럴 을 사용하여 작성할 수 있습니다.

type Point struct { X, Y int }
p := Point{1, 2}

위의 예는 모든 필드를 올바른 순서로 지정합니다. 프로그래머가 정확한 필드를 순서대로 기억해야하기 때문에 유용하지 않습니다. 종종 필드 이름과 해당 값의 일부 또는 전체를 나열하여 구조체를 초기화 할 수 있습니다.

anim := gif.GIF{LoopCount: nframes}

생략 된 필드는 해당 유형의 0 값으로 설정됩니다.

주 : 두 개의 형식은 동일한 리터럴에서 혼합 될 수 없습니다.

빈 구조체

구조체는 필드라고하는 명명 된 요소의 시퀀스이며 각 필드에는 이름과 유형이 있습니다. 빈 구조체에는 다음과 같은 익명의 빈 구조체와 같은 필드가 없습니다.

var s struct{}

또는 다음과 같이 빈 구조체 유형을 지정합니다.

type T struct{}

빈 구조체에 대한 흥미로운 점은 그 크기가 0입니다 ( Go The Playground 시도).

fmt.Println(unsafe.Sizeof(s))

0 출력하므로 빈 구조체 자체는 메모리를 사용하지 않습니다. 그래서 채널을 끝내기위한 좋은 옵션입니다 ( The Playground을 시도하십시오) :

package main

import (
    "fmt"
    "time"
)

func main() {
    done := make(chan struct{})
    go func() {
        time.Sleep(1 * time.Second)
        close(done)
    }()

    fmt.Println("Wait...")
    <-done
    fmt.Println("done.")
}



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow