# git config —global \
—add (—replace-all) \
url.https://kangseongsu:${Code}@my-gitlab.io:8001.insteadOf \
https://h-gitlab.io

위 처럼 지정해주면 port 및 인증 없이 clone등이 가능해진다.

# go env -w GOPRIVATE=h-gitlab.io

이번엔 위에서 지정한 host를 private repo로 설정해준다

# go get my-gitlab.io/myGroup/myproject.git

(.git은 일종의 트릭...?인데 분석은 생략한다)

Go get도 잘 되고 mod파일에도 잘 등록이 된다.

'language, framework, library > golang' 카테고리의 다른 글

gRPC  (0) 2020.02.13
[golang] protocoll buffer  (0) 2019.10.05
[Golang] sql  (0) 2019.08.21
[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] time  (0) 2019.08.08

Go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway

# Make
protoc -I.\
-I ${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
—go_out=plugins=grpc:. \
—grpc-gateway_out=logtostderr=true:. \
proto/blog.proto

'language, framework, library > golang' 카테고리의 다른 글

[Golang] go module 에서 private repo 이용하기  (0) 2020.05.08
[golang] protocoll buffer  (0) 2019.10.05
[Golang] sql  (0) 2019.08.21
[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] time  (0) 2019.08.08

1. generate

protoc --go_out=plugins=grpc:{b} {a}

a: proto 파일의 경로

b: a경로를 기준으로한, generate된 코드가 나올 경로

 

2. language

잠시 보다보면 별거 없다.

syntax = "proto3";

package protocol;

//interface (golang기준)
service UserService {
    rpc ListUser(ListUserRequestType) returns (ListUserResponseType) {}
    rpc RegisterUser(RegisterUserRequestType) returns (RegisterUserResponseType) {}
}

//struct
message User {
	//field
    string id = 1;
    string email = 2;
}

//Request
message ListUserRequestType {
}

//Response
//어려울 것 없다. 그냥 서버사이드의 request, response 객체 느낌 생각하면 된다.
message ListUserResponseType {
	//slice(array) 아래 #1 참조
    repeated User users =1;
}


message RegisterUserRequestType {
    string email = 1;
}

message RegisterUserResponseType {
}

/*
#1

If a field is repeated, the field may be repeated any number of times (including zero).
The order of the repeated values will be preserved in the protocol buffer.
Think of repeated fields as dynamically sized arrays.

*/

이걸 generate하면

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: app/interface/rpc/v1.0/protocol/user_service.proto

package protocol

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"

import (
	context "golang.org/x/net/context"
	grpc "google.golang.org/grpc"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package

type User struct {
	Id                   string   `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
	Email                string   `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *User) Reset()         { *m = User{} }
func (m *User) String() string { return proto.CompactTextString(m) }
func (*User) ProtoMessage()    {}
func (*User) Descriptor() ([]byte, []int) {
	return fileDescriptor_user_service_8e150b7eb2f667ef, []int{0}
}
func (m *User) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_User.Unmarshal(m, b)
}
func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_User.Marshal(b, m, deterministic)
}
func (dst *User) XXX_Merge(src proto.Message) {
	xxx_messageInfo_User.Merge(dst, src)
}
func (m *User) XXX_Size() int {
	return xxx_messageInfo_User.Size(m)
}
func (m *User) XXX_DiscardUnknown() {
	xxx_messageInfo_User.DiscardUnknown(m)
}

var xxx_messageInfo_User proto.InternalMessageInfo

func (m *User) GetId() string {
	if m != nil {
		return m.Id
	}
	return ""
}

func (m *User) GetEmail() string {
	if m != nil {
		return m.Email
	}
	return ""
}

type ListUserRequestType struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListUserRequestType) Reset()         { *m = ListUserRequestType{} }
func (m *ListUserRequestType) String() string { return proto.CompactTextString(m) }
func (*ListUserRequestType) ProtoMessage()    {}
func (*ListUserRequestType) Descriptor() ([]byte, []int) {
	return fileDescriptor_user_service_8e150b7eb2f667ef, []int{1}
}
func (m *ListUserRequestType) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListUserRequestType.Unmarshal(m, b)
}
func (m *ListUserRequestType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListUserRequestType.Marshal(b, m, deterministic)
}
func (dst *ListUserRequestType) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListUserRequestType.Merge(dst, src)
}
func (m *ListUserRequestType) XXX_Size() int {
	return xxx_messageInfo_ListUserRequestType.Size(m)
}
func (m *ListUserRequestType) XXX_DiscardUnknown() {
	xxx_messageInfo_ListUserRequestType.DiscardUnknown(m)
}

var xxx_messageInfo_ListUserRequestType proto.InternalMessageInfo

type ListUserResponseType struct {
	Users                []*User  `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListUserResponseType) Reset()         { *m = ListUserResponseType{} }
func (m *ListUserResponseType) String() string { return proto.CompactTextString(m) }
func (*ListUserResponseType) ProtoMessage()    {}
func (*ListUserResponseType) Descriptor() ([]byte, []int) {
	return fileDescriptor_user_service_8e150b7eb2f667ef, []int{2}
}
func (m *ListUserResponseType) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListUserResponseType.Unmarshal(m, b)
}
func (m *ListUserResponseType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListUserResponseType.Marshal(b, m, deterministic)
}
func (dst *ListUserResponseType) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListUserResponseType.Merge(dst, src)
}
func (m *ListUserResponseType) XXX_Size() int {
	return xxx_messageInfo_ListUserResponseType.Size(m)
}
func (m *ListUserResponseType) XXX_DiscardUnknown() {
	xxx_messageInfo_ListUserResponseType.DiscardUnknown(m)
}

var xxx_messageInfo_ListUserResponseType proto.InternalMessageInfo

func (m *ListUserResponseType) GetUsers() []*User {
	if m != nil {
		return m.Users
	}
	return nil
}

type RegisterUserRequestType struct {
	Email                string   `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *RegisterUserRequestType) Reset()         { *m = RegisterUserRequestType{} }
func (m *RegisterUserRequestType) String() string { return proto.CompactTextString(m) }
func (*RegisterUserRequestType) ProtoMessage()    {}
func (*RegisterUserRequestType) Descriptor() ([]byte, []int) {
	return fileDescriptor_user_service_8e150b7eb2f667ef, []int{3}
}
func (m *RegisterUserRequestType) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_RegisterUserRequestType.Unmarshal(m, b)
}
func (m *RegisterUserRequestType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_RegisterUserRequestType.Marshal(b, m, deterministic)
}
func (dst *RegisterUserRequestType) XXX_Merge(src proto.Message) {
	xxx_messageInfo_RegisterUserRequestType.Merge(dst, src)
}
func (m *RegisterUserRequestType) XXX_Size() int {
	return xxx_messageInfo_RegisterUserRequestType.Size(m)
}
func (m *RegisterUserRequestType) XXX_DiscardUnknown() {
	xxx_messageInfo_RegisterUserRequestType.DiscardUnknown(m)
}

var xxx_messageInfo_RegisterUserRequestType proto.InternalMessageInfo

func (m *RegisterUserRequestType) GetEmail() string {
	if m != nil {
		return m.Email
	}
	return ""
}

type RegisterUserResponseType struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *RegisterUserResponseType) Reset()         { *m = RegisterUserResponseType{} }
func (m *RegisterUserResponseType) String() string { return proto.CompactTextString(m) }
func (*RegisterUserResponseType) ProtoMessage()    {}
func (*RegisterUserResponseType) Descriptor() ([]byte, []int) {
	return fileDescriptor_user_service_8e150b7eb2f667ef, []int{4}
}
func (m *RegisterUserResponseType) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_RegisterUserResponseType.Unmarshal(m, b)
}
func (m *RegisterUserResponseType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_RegisterUserResponseType.Marshal(b, m, deterministic)
}
func (dst *RegisterUserResponseType) XXX_Merge(src proto.Message) {
	xxx_messageInfo_RegisterUserResponseType.Merge(dst, src)
}
func (m *RegisterUserResponseType) XXX_Size() int {
	return xxx_messageInfo_RegisterUserResponseType.Size(m)
}
func (m *RegisterUserResponseType) XXX_DiscardUnknown() {
	xxx_messageInfo_RegisterUserResponseType.DiscardUnknown(m)
}

var xxx_messageInfo_RegisterUserResponseType proto.InternalMessageInfo

func init() {
	proto.RegisterType((*User)(nil), "protocol.User")
	proto.RegisterType((*ListUserRequestType)(nil), "protocol.ListUserRequestType")
	proto.RegisterType((*ListUserResponseType)(nil), "protocol.ListUserResponseType")
	proto.RegisterType((*RegisterUserRequestType)(nil), "protocol.RegisterUserRequestType")
	proto.RegisterType((*RegisterUserResponseType)(nil), "protocol.RegisterUserResponseType")
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4

// UserServiceClient is the client API for UserService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type UserServiceClient interface {
	ListUser(ctx context.Context, in *ListUserRequestType, opts ...grpc.CallOption) (*ListUserResponseType, error)
	RegisterUser(ctx context.Context, in *RegisterUserRequestType, opts ...grpc.CallOption) (*RegisterUserResponseType, error)
}

type userServiceClient struct {
	cc *grpc.ClientConn
}

func NewUserServiceClient(cc *grpc.ClientConn) UserServiceClient {
	return &userServiceClient{cc}
}

func (c *userServiceClient) ListUser(ctx context.Context, in *ListUserRequestType, opts ...grpc.CallOption) (*ListUserResponseType, error) {
	out := new(ListUserResponseType)
	err := c.cc.Invoke(ctx, "/protocol.UserService/ListUser", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *userServiceClient) RegisterUser(ctx context.Context, in *RegisterUserRequestType, opts ...grpc.CallOption) (*RegisterUserResponseType, error) {
	out := new(RegisterUserResponseType)
	err := c.cc.Invoke(ctx, "/protocol.UserService/RegisterUser", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// UserServiceServer is the server API for UserService service.
type UserServiceServer interface {
	ListUser(context.Context, *ListUserRequestType) (*ListUserResponseType, error)
	RegisterUser(context.Context, *RegisterUserRequestType) (*RegisterUserResponseType, error)
}

func RegisterUserServiceServer(s *grpc.Server, srv UserServiceServer) {
	s.RegisterService(&_UserService_serviceDesc, srv)
}

func _UserService_ListUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ListUserRequestType)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(UserServiceServer).ListUser(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/protocol.UserService/ListUser",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(UserServiceServer).ListUser(ctx, req.(*ListUserRequestType))
	}
	return interceptor(ctx, in, info, handler)
}

func _UserService_RegisterUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(RegisterUserRequestType)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(UserServiceServer).RegisterUser(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/protocol.UserService/RegisterUser",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(UserServiceServer).RegisterUser(ctx, req.(*RegisterUserRequestType))
	}
	return interceptor(ctx, in, info, handler)
}

var _UserService_serviceDesc = grpc.ServiceDesc{
	ServiceName: "protocol.UserService",
	HandlerType: (*UserServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "ListUser",
			Handler:    _UserService_ListUser_Handler,
		},
		{
			MethodName: "RegisterUser",
			Handler:    _UserService_RegisterUser_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "app/interface/rpc/v1.0/protocol/user_service.proto",
}

func init() {
	proto.RegisterFile("app/interface/rpc/v1.0/protocol/user_service.proto", fileDescriptor_user_service_8e150b7eb2f667ef)
}

var fileDescriptor_user_service_8e150b7eb2f667ef = []byte{
	// 249 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x4f, 0xcd, 0x4a, 0xc3, 0x40,
	0x10, 0x76, 0xa3, 0x95, 0x3a, 0x95, 0x1e, 0xc6, 0x8a, 0x21, 0xa0, 0xd4, 0xc5, 0x43, 0x0f, 0x92,
	0xd5, 0x78, 0xf5, 0x0d, 0xf4, 0x14, 0x15, 0x8f, 0x12, 0xd3, 0x51, 0x16, 0x6a, 0xb3, 0xee, 0x6c,
	0x0b, 0x3e, 0x97, 0x2f, 0x28, 0xbb, 0x21, 0x6c, 0x2c, 0xed, 0x71, 0xbe, 0xf9, 0x7e, 0xa1, 0xa8,
	0x8c, 0x51, 0x7a, 0xe9, 0xc8, 0x7e, 0x54, 0x35, 0x29, 0x6b, 0x6a, 0xb5, 0xbe, 0xcd, 0x6f, 0x94,
	0xb1, 0x8d, 0x6b, 0xea, 0x66, 0xa1, 0x56, 0x4c, 0xf6, 0x8d, 0xc9, 0xae, 0x75, 0x4d, 0x79, 0x40,
	0x71, 0xd8, 0x3d, 0xe5, 0x35, 0x1c, 0xbc, 0x30, 0x59, 0x1c, 0x43, 0xa2, 0xe7, 0xa9, 0x98, 0x8a,
	0xd9, 0x51, 0x99, 0xe8, 0x39, 0x4e, 0x60, 0x40, 0x5f, 0x95, 0x5e, 0xa4, 0x49, 0x80, 0xda, 0x43,
	0x9e, 0xc2, 0xc9, 0xa3, 0x66, 0xe7, 0x15, 0x25, 0x7d, 0xaf, 0x88, 0xdd, 0xf3, 0x8f, 0x21, 0x79,
	0x0f, 0x93, 0x08, 0xb3, 0x69, 0x96, 0x4c, 0x1e, 0xc7, 0x2b, 0x18, 0xf8, 0x70, 0x4e, 0xc5, 0x74,
	0x7f, 0x36, 0x2a, 0xc6, 0x79, 0x17, 0x9b, 0x07, 0x6a, 0xfb, 0x94, 0x0a, 0xce, 0x4a, 0xfa, 0xd4,
	0xec, 0xc8, 0x6e, 0x18, 0xc7, 0x16, 0xa2, 0xdf, 0x22, 0x83, 0xf4, 0xbf, 0x20, 0x46, 0x16, 0xbf,
	0x02, 0x46, 0x1e, 0x7c, 0x6a, 0xf7, 0xe2, 0x03, 0x0c, 0xbb, 0x6a, 0x78, 0x1e, 0xf3, 0xb7, 0xac,
	0xc8, 0x2e, 0xb6, 0xbd, 0xa3, 0xb5, 0xdc, 0xc3, 0x57, 0x38, 0xee, 0x07, 0xe3, 0x65, 0x54, 0xec,
	0x58, 0x90, 0xc9, 0x5d, 0x94, 0xbe, 0xf1, 0xfb, 0x61, 0x20, 0xdd, 0xfd, 0x05, 0x00, 0x00, 0xff,
	0xff, 0x6d, 0x19, 0x74, 0x30, 0xcc, 0x01, 0x00, 0x00,
}

 

the code comes out like this. 잘 보면 interface로 UserServiceServer, UserServiceClient가 존재한다.

아래는 위 소스를 우리가 사용해야하는 부분 위주로 간츄려 본 것이다.

//struct가 정의 된다.
type User struct
func (m *User) GetId() string
func (m *User) GetEmail() string

//request에는 담아 보낼게 없었으므로
type ListUserRequestType struct

//response는 User 배열을 나른다.
type ListUserResponseType struct
func (m *ListUserResponseType) GetUsers() []*User

//email을 나른다.
type RegisterUserRequestType struct
func (m *RegisterUserRequestType) GetEmail() string

type RegisterUserResponseType struct

//client나 server는 protobuff의 service부분을 이용해 각각의 interface를 만들어 가진다.
//서로 다른 점이라 한다면, client는 grpc.ClientConn을 필드 오브젝트로 가진 struct가 존재하며,
//server는 Handler를 가지는데 위 전체 소스에서 볼 수있듯이 concret object를 받아 usecase를 구현해 사용한다.
type UserServiceClient interface
type userServiceClient struct
func NewUserServiceClient(cc *grpc.ClientConn) UserServiceClient
func (c *userServiceClient) ListUser(ctx context.Context, in *ListUserRequestType, opts ...grpc.CallOption) (*ListUserResponseType, error)
func (c *userServiceClient) RegisterUser(ctx context.Context, in *RegisterUserRequestType, opts ...grpc.CallOption) (*RegisterUserResponseType, error)

type UserServiceServer interface
func RegisterUserServiceServer(s *grpc.Server, srv UserServiceServer)
func _UserService_ListUser_Handler(srv interface, ctx context.Context, dec func(interface) error, interceptor grpc.UnaryServerInterceptor) (interface, error)
func _UserService_RegisterUser_Handler(srv interface, ctx context.Context, dec func(interface) error, interceptor grpc.UnaryServerInterceptor) (interface, error)

 

3. 후기

protocol buffer는 기본적으로 proto파일을 정의하고 그에 맞게 소스를 generate하여 사용한다.

협업시에 이용한다면 proto파일을 정의문서로도 사용하기 좋을것 같고, usecase구현 부분만 잘 관리하면 의존성이라던가 하는 여러 귀찮은 요소들이 깔끔하게 정리 될 수있을 것 같다.

 

신기술 탐방삼아 구현해본 grpc이므로 벤치마크등의 성능테스트는 생략한다.

비교해놓은 사람들 많으니 google에 검색해보자!

시간나면 rest vs grpc vs graphql을 제대로 한번 비교 해 보고싶다

'language, framework, library > golang' 카테고리의 다른 글

[Golang] go module 에서 private repo 이용하기  (0) 2020.05.08
gRPC  (0) 2020.02.13
[Golang] sql  (0) 2019.08.21
[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] time  (0) 2019.08.08

// import

import (

    "database/sql"

    _ "github.com/lib/pq"

)

 

// basement logic

connectionString := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%s", ...)

db, err := sql.Open("postgres", connectionString)

if err = db.Ping(); err != nil { ... }

 

 

export TEST_DB_USERNAME=admin && \
export TEST_DB_PASSWORD=admin && \
export TEST_DB_NAME=postgres && \
export TEST_DB_HOST=127.0.0.1 && \
export TEST_DB_PORT=5432

'language, framework, library > golang' 카테고리의 다른 글

gRPC  (0) 2020.02.13
[golang] protocoll buffer  (0) 2019.10.05
[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] time  (0) 2019.08.08
[Golang] 객체지향  (0) 2019.08.05
func Example_A() {
var a []func() int
for i := 0; i < 5; i++ {
a= append(a, func() int {
return i
})

}
for _, f := range a {
fmt.Println(f())
}

//Output:
//5
//5
//5
//5
//5
}

위 식은 0,1,2,3,4를 출력 할 것 같지만, 실제로는 5,5,5,5,5를 출력한다. 

함수를 리턴하기 때문이며, 클로져는 외부함수가 없어지는 순간의 환경을 기억한다.

외부환경이 없어지는 순간 i는 5이다. 

내부함수는 i를 참조하고 있는거지 i가 0,1,2,3,4 였었던 때의 값을 가지고 있는 것이 아니다.

그렇기에 마지막 환경속 i는 5가 되어 for를 돌리지 못하고 끝이 나기때문에  5만 5개 출력한다.

//javascript와 달리 람다의 뒤에 (i)처럼 실행 인자를 미리 넣어주면,
//그것은 반환되기 전 처리되기 때문에 이미 int type이다.
func Example_B() {
var a []int
for i := 0; i < 5; i++ {
a= append(a, func(id int) int {
return id
}(i))

}
for _, f := range a {
fmt.Println(f)
}

//Output:
//0
//1
//2
//3
//4
}

앞서 보았던 함수를 정상적으로 돌게 하기 위한 방법이다.

i를 id에 할당하여 바로바로 넣어준다.

func C(b bool) func(fr string) []string {
	var arr []string
	if b {
		return func(fr string) []string {
			for i := 0; i < 5; i++ {
				arr = append(arr, fmt.Sprintf("%s : %d", fr, i))
			}
			return arr
		}
	}
	return func(fr string) []string {
		arr = append(arr, fmt.Sprintf("%s : 0", fr))
		return arr
	}
}

이번에는 살짝 살을 더 붙여 보았다.

func Example_C() {
	d := closure.B(true)
	arr1 := d("apple")
	for _, apple := range arr1{
		fmt.Println(apple)
	}
	arr2 := d("banana")
	for _, banana:= range arr2{
		fmt.Println(banana)
	}
	//Expected Output:
	//apple : 0
	//apple : 1
	//apple : 2
	//apple : 3
	//apple : 4
	//banana : 0
	//banana : 1
	//banana : 2
	//banana : 3
	//banana : 4

	//Output:
	//apple : 0
	//apple : 1
	//apple : 2
	//apple : 3
	//apple : 4
	//apple : 0
	//apple : 1
	//apple : 2
	//apple : 3
	//apple : 4
	//banana : 0
	//banana : 1
	//banana : 2
	//banana : 3
}

위 코드를 실행 시키면 어떻게 될까?

생각을 짧게하면 Expected Output: 과 같은 결과를 원할 수있다.

하지만 결과는 Output: 과 같다.

 

그 이유는 역시 arr이라는 free variable이라는 환경을 공유하기 때문이다.

그리고 A와 B에서 처럼 for문에 의해 4,4,4,4,4만 찍혔을 것이라 착각 할수도 있는데

이번에는 for문 또한 bound variable임을 이해하면 쉽다.

'language, framework, library > golang' 카테고리의 다른 글

[golang] protocoll buffer  (0) 2019.10.05
[Golang] sql  (0) 2019.08.21
[Golang] time  (0) 2019.08.08
[Golang] 객체지향  (0) 2019.08.05
[Golang] Discovery go 8장 리딩  (0) 2019.07.31

time.Duration : int64, Nano Second

time.Duration(1,000) = Micro Second

time.Duration(1,000,000) = Milli Second

time.Duration(1,000,000,000) = Second

 

time.Second

time.Microsecond

time.Millisecond

 

time.Sleep(D duration)

 

time.Now()

'language, framework, library > golang' 카테고리의 다른 글

[Golang] sql  (0) 2019.08.21
[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] 객체지향  (0) 2019.08.05
[Golang] Discovery go 8장 리딩  (0) 2019.07.31
[Golang] Handle, HandlerFunc 그리고 path  (0) 2019.07.24

Golang은 객체지향을 완전히 지원하지는 않지만 충분히 사용 가능

 

1. 다형성 :

객체지향의 꽃, 객체가 메서드에 대한 다향한 구현을 가지게 함. go의 인터페이스로 쉽게 구현이 가능 ,메서드만 구현하면 인터페이스로 사용이 가능하기 때문에 더 쉽게 구현이 가능

2. 상속 :

어떤 클래스의 구현들을 재 사용하기위하여 사용. IsA 관계와 HasA관계가 성립

HasA - 구조체를 필드로 내장

IsA - 인터페이스와 구조체 내장을 함께 사용

3. 캡슐화 

- 객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 외부에 감추는 것

- 외부 객체는 객체 내부이 구조를 얻지 못하며 객체가 노출해서 제공하는 필드와 메소드만 이용할 수 있다.

- 필드와 메소드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는데 있다.

Golang에서는 name값의 첫 문자의 대소문자로 노출 여부를 결정한다.

또 internal폴더를 사용하면 경로에 internal이 없는 경우 외부에서 참조할 수 없게 만들 수있다.

 

package main

import (
	"fmt"
	"reflect"
)

type Shape interface {
	Area() float32
}

type Rectangle struct {
	Width, Height float32
}

// IsA 상속이 되려면 이 메서드가 Rectangle이 들어가는 곳에 들어갈 수 있어야한다.
// Golang 에서는 이를 interface 구현을 이용한다.
func (r Rectangle) Area() float32 {
	return r.Width * r.Height
}

func TotalArea(s []Shape) float32 {
	var totalArea float32
	for _, sh := range s {
		totalArea += sh.Area()
	}
	return totalArea
}

// HasA
type RectangleInherit struct {
	Rectangle
}

func (r RectangleInherit) Circum() float32 {
	return 2 * (r.Width * r.Height)
}

//// Overriding, 주석 풀면 결과는 420 + 210 = 630이 됨
//func (r RectangleInherit) Area() float32 {
//	return r.Width * r.Height * 2
//}

// Constructor
func NewRectangleInherit(w, h float32) *RectangleInherit {
	return &RectangleInherit{Rectangle{
		Width:  w,
		Height: h,
	}}
}

func main() {
	res := TotalArea(
		[]Shape{
			//SubType, RectangleInherit이 Area()를 가진 것은 아니지만 Shape구현체로 사용가능
			NewRectangleInherit(14, 15),
			Rectangle{
				Width:  14,
				Height: 15,
			},
		},
	)
	fmt.Println(res)
	// 210 + 210 = 420


	//reflect implements confirm
	impl := reflect.TypeOf(NewRectangleInherit(1,2)).Implements(reflect.TypeOf((*Shape)(nil)).Elem())
	fmt.Println(impl)
	//true

	field, ok := reflect.TypeOf(RectangleInherit{}).FieldByName("Rectangle")
	emb := ok && field.Anonymous && field.Type == reflect.TypeOf(Rectangle{})
	fmt.Println(emb)
	//true
}

 

 

'language, framework, library > golang' 카테고리의 다른 글

[Golang] 클로져, 람다  (0) 2019.08.08
[Golang] time  (0) 2019.08.08
[Golang] Discovery go 8장 리딩  (0) 2019.07.31
[Golang] Handle, HandlerFunc 그리고 path  (0) 2019.07.24
[Golang] json의 null  (0) 2019.06.17

8. 실무와 관련한 패턴

  이전에 하던 것을 go에서 어떻게 하느냐 보다 어떤 문제를 풀려고 하는지가 중요하다. 생각을 폭 넓게!

8.1 오버로딩

  오버로딩은 없지만, 그 문제를 어떻게 해결하느냐가 중요

  a. 자료형에따라 다른 이름 붙이기 : 오버로딩을 반드시 할 필요 없는 경우

  b. 가변인자 이용 : 동일한 자료형의 자료 개수에 따른 오버로딩

  c. 자료형 스위치 활용 : 오버로딩을 반드시 해야하는 경우 인터페이스를 인자로 받아 메서드 내에서 자료형 스위치로        다른 자료형에 맞추어 다른 코드가 수행 되도록 한다.

  d. 구조체 넘기기 : 편의를 위하여 오버로딩을 하는 경우, 코드의 가독성을 위한 경우

  e. 인터페이스 활용 : c의 경우를 포함하여 인터페이스가 유리한 경우가 있다.

8.2.1 템플릿 및 제네릭 프로그래밍

  Go는 제네릭을 지원하지 않는다.

  a. interface{}의 활용

  b. 테스트의 경우 테이블기반 테스팅

8.2.2 컨테이너 알고리즘

  

'language, framework, library > golang' 카테고리의 다른 글

[Golang] time  (0) 2019.08.08
[Golang] 객체지향  (0) 2019.08.05
[Golang] Handle, HandlerFunc 그리고 path  (0) 2019.07.24
[Golang] json의 null  (0) 2019.06.17
[Golang] coverage  (0) 2019.06.12

golang을 사용하다보면 한동안 아래 두가지가 헷갈린다.

 

a. http.HandlerFunc(pattern string, handler func(ResponseWriter, *Request))

b. http.Handle(pattern string, handler Handler)

 

일단 위 명세를 보면 얼핏 pattern, hanlder를 똑같이 인자로 받는 것 처럼 보인다.

하지만 두개를 같이 놓고 보면 확실히 handler가 받는 type부터가 서로 다르다. 위는 function, 아래는 interface.

type Handler interface{

    ServeHTTP(ResponseWriter, *Request)

}

 

a는 function을 받아 해당 pattern으로 들어오는 요청을 직접 처리해주는 경우이며,

b는 미리 구성한 mux등을 사용할때 이용한다.

 

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

http.Handle("/css/", http.FileServer(http.Dir("web")))

http.Dir뒤의 위치가 root다 

그리고 위 Handle의 path자리에 위치한 "/css/"는 root뒤에 붙는 주소이다.

 

#http

type Dir string
A Dir implements FileSystem using the native file system restricted to a specific directory tree.
While the FileSystem.Open method takes '/'-separated paths, a Dir's string value is a filename on the native file system, not a URL, so it is separated by filepath.Separator, which isn't necessarily '/'.
Note that Dir will allow access to files and directories starting with a period, which could expose sensitive directories like a .git directory or sensitive files like .htpasswd. To exclude files with a leading period, remove the files/directories from the server or create a custom FileSystem implementation.
An empty Dir is treated as ".".

 

'language, framework, library > golang' 카테고리의 다른 글

[Golang] 객체지향  (0) 2019.08.05
[Golang] Discovery go 8장 리딩  (0) 2019.07.31
[Golang] json의 null  (0) 2019.06.17
[Golang] coverage  (0) 2019.06.12
[Golang] 임베딩(Is-a), delegation  (0) 2019.06.11

golang의 struct

{

  Name: "kss",

  Age : 17,

  ExpiredDate : nil,

}

 

json

{

  "Name": "kss",

  "Age" : 17,

  "ExpiredDate" : null,

}

 

golang에서는 nil 이라는 값이 json에서는 null이다.

 

json.Marshal에서는 알아서 이런 전환을 처리해준다.

만약 json interface를 사용할 경우

MarshalJSON()에서는 "null"을 []byte로 return시켜주고,

UnmarshalJSON()에서는 받은 "null"을  아래와 같이 처리해 주면 v에는 nil 값이 나오게 된다.

var v interface{}
json.Unmarshal([]byte("null"), &v)
// v == nil
json.Unmarshal([]byte("nil"), &v)
// error

"nil"은 json에서는 type이 아님을 주의

 

'language, framework, library > golang' 카테고리의 다른 글

[Golang] Discovery go 8장 리딩  (0) 2019.07.31
[Golang] Handle, HandlerFunc 그리고 path  (0) 2019.07.24
[Golang] coverage  (0) 2019.06.12
[Golang] 임베딩(Is-a), delegation  (0) 2019.06.11
[Golang] Instance  (0) 2019.06.11

+ Recent posts