Struct

이번에는 니꼬쌤이 설명해주신 struct라는 개념이 잘 이해되지 않아서 인터넷을 활용해 직접 찾아보았다

 

 내가 생각하는 struct(아니라면 태클 부탁드립니다) : Go는 전통적인 객체지향 언어라고 불리는 파이썬, 자바, 자바스크립트, 씨플플 등이 가지고 있는 클래스, 객체, 상속과 같은 개념이 없는 언어 (싹수없다는 거 아님) 하지만 클래스의 역할을 하는 것이 바로 struct.   니꼬쌤은  struct는 object와 비슷하면서 map보다는 유연한 것이라고 하셨다 그럼 다른 언어들에서 클래스, 객체, 상속이 도대체 뭘까? 그걸 알면 struct도 알 수 있지 않을까? 해서 찾아본 결과 아!! 이게 말로만 듣던 붕어빵과 붕어빵 틀 아빠와 아들 이야기구나 했다 

 

 클래스와 객체를 설명하기 위해 사과를 예로 들자면 사과하면 떠오르는 물체가 있을 텐데 그것을 이상적인 형태의 사과라고 했을 때 실제로 먹는 사과는 떠오르는 사과와 완벽하게 일치하지는 않는다 하지만 우리는 그것을 사과라고 인식한다 여기서 사과하면 떠오르는 물체가 바로 클래스이고 실제로 먹는 사과들이 바로 객체(object)이다 붕어빵과 붕어빵 틀로는 붕어빵 틀이 클래스 실제로 먹는 붕어빵이 객체(object)인 것이다 붕어빵이 굽히는 과정상속받는다라고 말할 수 있다 찾다 보니 진짜 설명 잘하신 분이 있어서 https://youtu.be/vrhIxBWSJ04 공유한다

 

 struct가 클래스와 비슷한 역할을 한다면 이제는 좀 이해가 된다 형태를 보면 이해가 더 잘 될 것이다

person이라는 struct를 만들었다 

type person struct {
    name string
    age	 int
    favFood []string
}

func main() {
	favFood := []string{"spam","ramen"}
    pavk :=person{name:"pavk",
    			age:25,
                  	favFood:favFood} (map이었다면 key와 value값이 각각 일정한 형태였을 것이다 )
   	fmt.Println(pavk.name)
}

//결과--> pavk

객체지향 언어로 봤을 때 person이라는 클래스와 pavk라는 객체(object)를 만든 것과 같다

 

일단은 지금과 같이 올리고 추후에 피드백과 더 많은 정보들을 찾아서 업데이트하도록 하겠다

 

(2020/03/16 수정)

Struct의 private과 public

 저번 package에서 알 수 있듯이 가져오기(import)한 패키지 중 보이는 것도 있고 아닌 것도 있다는 것을 우리는 알고 있다 대문자와 소문자로 그것을 구분하는데 대문자인 경우에는 public(보이는 것, 공용), 소문자인 경우에는 private(보이지 않는 것, 개인)이다 마찬가지로 struct, object도 이것이 포함된다 

 

 니꼬쌤은 은행계좌를 예로 들어주셨다

니꼬쌤이 하고자 하신 것은 1. 계좌 만들기 2. 다른 사람들이 함부로 쓸 수 없도록 만들기 3. 입출금 하기 및 잔액조회이다

 

 우선 struct자체를 컴파일할 것이 아니기 때문에 main함수는 만들지 아니한다

accounts라는 폴더와 accounts.go라는 파일을 만들어준 후 struct를 만든다 단 이폴더는 앞서 만들었던 learngo폴더 안에 만들어야 한다 왜냐하면 다른 폴더에 있으면 가져오기(import)가 되지 않는다

 

 위에서 보면 알 수 있다시피 type문을 활용해 struct를 생성해주고 객체(object), 객체 유형을 적어준다 

package accounts

type account struct {
	owner   string
	balance int
}

 main.go에서 코드를 작성해보면 알겠지만 account도 owner도 balance도 나타나지 않는다 private이기 때문이다 

그렇다고 대문자로 바꾸어서 public으로 만들어 버리면 다른 사람들이 함부로 쓸 수 있게 된다 그럼 private이면서 계좌를 생성할 수 있는 방법은?? 바로 함수와 포인터를 사용하는 것이다 

 

 NewAccount라는 함수를 만들어 account값을 반환해보도록 하자

package accounts

type Account struct {
	owner   string
	balance int
}

func NewAccount(owner string) *Account { //함수명이 대문자인 이유: public, main.go에서 호출하기 위해서!
	account := Account{owner: owner, balance: 0}
	return &account 
}

 위 코드에서 볼 수 있듯 함수의 반환하는 타입은 씨쓰루(*) 반환 값은 주소 값(&)이다 포인터를 사용한 이유는 만약 복사를 했다면 똑같이 private으로 나와서 사용할 수 없다 하지만 포인터형으로 반환을 한다면 결과는 이렇게 잘 나오게 된다

Struct와 Method

 앞서 private과 public을 계좌 만드는 것을 통해 알아봤다면 이번에는 Method를 입출금 및 잔액조회를 통해 알아보려고 한다 method는 간단하게 말하자면 기능이다 struct안에서 쓸 수 있는 기능이라고 생각하면 된다 함수와 정말 비슷하게 생겼다 다만 receiver라는 인자를 함수명과 func사이에 적어줘야 한다 receiver의 유형에는 Account가 들어간다 아마도 이 struct와 연결된 method라는 것을 인지 하기 위해 이렇게 하는 것이 아닐까 한다 한 가지! receiver에 들어가는 인자는 아무 이름이나 적어도 되지만 struct의 첫 글자의 소문자를 따와서 적는 것을 원칙으로 한다

 

 입출금과 잔액조회 method를 만들어준다

func (a/*인자이름*/ Account/*인자 유형*/) Deposit(amount int) {//입급 +
	a.balance += amount
}

func (a Account) Balance() int { //잔액조회용
	return a.balance
}
func (a Account) Withdraw(amount int) { //출금 -
	a.balance -= amount
}

 

 그다음 main.go에서 실행을 해주면?? 값이 0이 되어있다 그 이유는 receiver에 struct Account를 복사한 것이기 때문이다 그냥 복사해왔기 때문에 원래 값을 가지게 된다 그럼 여기서 필요한 것은?? 

포인터이다!! Account 앞에 *를 붙여줘서 씨쓰루 해주고 다시 실행해보면

잘 된 것을 볼 수 있다 

 

 그런데 계좌에서 마이너스는  허용되지 않는 다 잔액부족이라고 에러가 뜨지 그래서 니꼬쌤은 에러를 만들기로 했다 

출금할 때 출금할 돈이 잔액보다 많으면 에러가 뜨므로 if문을 통해 이렇게 만들어 준다 

func (a *Account) Withdraw(amount int) error {//반환 유형은 error
	if a.balance < amount {
		return errors.New("Can't withdraw")
	}
	a.balance -= amount
	return nil //파이썬이나 자바스크립트의 none,null처럼 아무것도 없는 것을 반환한다 
    //error도 두가지 유형이 있는데 에러가 난경우 error 아닌경우 nil
}
func main() {
	account := accounts.NewAccount("pavk")
	account.Deposit(10)
	err := account.Withdraw(20)
	if err != nil {//error가 nil이 아닌경우 즉 에러가 난경우!
		log.Fatalln(err)
	}
	fmt.Println(account.Balance())

}

컴파일을 해보면

이런 결과가 나온다 

 

※Go는 에러가 날 만한 것들을 하나하나 이런 식으로 체크해주어야 한다 너무 많으면 변수로 깔끔하게 정리할 수 있다

 

마지막으로 깔끔하게 출력을 해보자

 

잔액조회를 위해선 계좌 주인의 이름과 잔액을 나란히 써주면 된다 

 

pavk's account : 10$ 이런식으로 말이다

 

Python에서는 클래스를 출력하면 클래스가 가진 매서드를 string형태로 출력한다 

 

마찬가지로 Go도 struct를 프린트하면 매서드를 string형태로 출력할 수 있는데 그 방법이 바로 String( ) 매서드이다

 

//Owner매서드가 없기 때문에 만들어준다

func (a Account) Owner() string {

    return a.owner

}

//String 매서드

func (a Account) String() string {

    return fmt.Sprint(a.Owner(), "'s account : ", a.Balance(), "$")

}

이렇게 String매서드를 작성해주고 (여기서 receiver인자에 *가 안 들어가는 이유는 변화하는 값이 없기 때문이다 private 하게 지켜줘야 한다는 뜻) main.go에서 account(struct)를 출력해주면 끝

이런 식으로 결과가 나온다!

'노마드코더스 아카데미 > Go언어로 웹스크래퍼 만들기' 카테고리의 다른 글

Dictionary use type in Go lang (feat. map)  (2) 2020.03.24
Go웹스크래핑[3]  (0) 2020.03.13
Go웹스크래핑[2]  (0) 2020.03.12
Go웹스크래핑[1]  (0) 2020.03.11
Go 웹스크래핑[0]  (0) 2020.03.11

+ Recent posts