Menu
Coddy logo textTech

구조체 포인터

Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 20번째.

구조체(struct)를 다룰 때, 큰 데이터 구조를 복사하는 것을 피하고 원본 구조체를 수정하기 위해 포인터를 자주 사용하게 됩니다. 구조체에 대한 포인터는 해당 구조체 인스턴스의 메모리 주소를 보유합니다.

기존 구조체에 & 연산자를 사용하거나, 구조체 리터럴과 함께 주소 연산자를 직접 사용하여 구조체 포인터를 생성할 수 있습니다.

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}
ptr := &p  // 기존 구조체에 대한 포인터

// 또는 직접 생성
ptr2 := &Person{Name: "Bob", Age: 25}

Go는 포인터를 통해 구조체 필드에 접근할 때 편리한 단축 방식을 제공합니다. (*ptr).Name이라고 쓰는 대신, 간단히 ptr.Name이라고 쓸 수 있습니다. Go가 자동으로 포인터를 역참조해 줍니다.

ptr := &Person{Name: "Alice", Age: 30}

// 둘 다 동일하게 작동합니다
fmt.Println((*ptr).Name)  // 명시적 역참조
fmt.Println(ptr.Name)     // 자동 역참조

이 자동 역참조는 필드를 수정할 때도 적용됩니다. 포인터를 통한 변경사항은 원본 구조체에 영향을 미칩니다.

p := Person{Name: "Alice", Age: 30}
ptr := &p

ptr.Age = 31           // 원본을 수정함
fmt.Println(p.Age)     // 31

구조체 포인터는 Go의 OOP 패턴에서 필수적입니다. 이는 메서드가 리시버 상태를 수정할 수 있게 하고, 대규모 구조체를 함수에 효율적으로 전달할 수 있도록 하며, 트리나 리스트와 같은 연결된 데이터 구조를 구축하기 위한 기초를 형성합니다.

challenge icon

챌린지

쉬움

구조체 포인터가 원본 데이터를 어떻게 효율적으로 수정할 수 있는지 보여주는 은행 계좌 시스템을 구축해 보겠습니다. 포인터 연산을 통해 업데이트할 수 있는 계좌를 만들게 됩니다.

코드는 두 개의 파일로 구성됩니다:

  • account.go: Owner (string), Balance (float64), AccountNumber (string) 필드를 가진 BankAccount 구조체를 정의합니다. 소유자 이름과 계좌 번호를 매개변수로 받아 시작 잔액이 0인 새로운 BankAccount에 대한 포인터를 반환하는 NewAccount 함수를 만듭니다. 또한 *BankAccount 포인터와 금액을 매개변수로 받아 포인터를 통해 해당 금액을 계좌 잔액에 추가하는 Deposit 함수를 만듭니다.
  • main.go: 입력으로부터 계좌 정보를 읽고, 생성자 함수(포인터를 반환함)를 사용하여 계좌를 생성하고, 포인터를 사용하여 입금을 진행한 후, 잔액이 수정되었는지 확인하기 위해 계좌 상세 정보를 표시합니다.

다음과 같은 입력이 제공됩니다:

  • Line 1: 소유자 이름
  • Line 2: 계좌 번호
  • Line 3: 입금 금액 (float)

출력 형식:

Account: [AccountNumber]
Owner: [Owner]
Balance: [Balance]

예를 들어, John Smith, ACC-12345, 500.50이 주어지면 출력은 다음과 같아야 합니다:

Account: ACC-12345
Owner: John Smith
Balance: 500.50

NewAccount 함수는 & 연산자를 사용하여 *BankAccount를 반환해야 하며, Deposit 함수는 Go의 자동 역참조(예: (*account).Balance 대신 account.Balance)를 사용하여 포인터를 통해 직접 잔액을 수정할 수 있음을 기억하세요.

치트 시트

구조체 포인터(pointer to a struct)는 구조체 인스턴스의 메모리 주소를 보유합니다. & 연산자를 사용하여 구조체 포인터를 생성합니다:

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}
ptr := &p  // 기존 구조체에 대한 포인터

// 또는 직접 생성
ptr2 := &Person{Name: "Bob", Age: 25}

Go는 포인터를 통해 구조체 필드에 접근할 때 자동 역참조(automatic dereferencing)를 제공합니다. (*ptr).Name 대신 ptr.Name이라고 쓸 수 있습니다:

ptr := &Person{Name: "Alice", Age: 30}

// 둘 다 동일하게 작동합니다
fmt.Println((*ptr).Name)  // 명시적 역참조
fmt.Println(ptr.Name)     // 자동 역참조

포인터를 통한 변경은 원본 구조체에 영향을 미칩니다:

p := Person{Name: "Alice", Age: 30}
ptr := &p

ptr.Age = 31           // 원본을 수정함
fmt.Println(p.Age)     // 31

구조체 포인터는 메서드가 수신자(receiver) 상태를 수정할 수 있게 하고, 큰 구조체를 함수에 효율적으로 전달할 수 있게 하며, 연결된 데이터 구조(linked data structures)의 기초를 형성합니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// 소유자 이름 읽기
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)
	
	// 계좌 번호 읽기
	accountNumber, _ := reader.ReadString('\n')
	accountNumber = strings.TrimSpace(accountNumber)
	
	// 입금액 읽기
	amountStr, _ := reader.ReadString('\n')
	amountStr = strings.TrimSpace(amountStr)
	amount, _ := strconv.ParseFloat(amountStr, 64)
	
	// TODO: NewAccount 함수를 사용하여 새 계좌 생성 (포인터 반환)
	
	// TODO: 계좌 포인터를 사용하여 Deposit 함수로 입금 수행
	
	// TODO: 다음의 필수 형식으로 계좌 상세 정보 출력:
	// 계좌: [AccountNumber]
	// 소유자: [Owner]
	// 잔액: [Balance]
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨