Golang 고 효율 실천 의 범 담 편

34143 단어
머리말
제 블 로그 이전의 Golang 효율 적 인 실천 시리즈 블 로그 에서 Golang 의 효율 적 인 실천 건 의 를 체계적으로 소 개 했 습 니 다. 예 를 들 어,,,,, 등 이 있 습 니 다.본 고 는 자질구레한 Golang 의 효율 적 인 실천 건 의 를 소개 할 것 이다. 비록 자질구레 하지만 비교적 중요 하 다.
건의 하 다.
1. 코드 형식 go fmt 도구, 개발 에 너무 신경 쓰 지 않 아 도 됩 니 다.
2. 블록 주석 과 줄 주석 을 지원 합 니 다. 일반 패키지 의 시작 부분 은 블록 주석 으로 설명 하고 함 수 는 줄 주석 으로 설명 합 니 다. 식별 도 를 높이 기 위해 함수 주석 은 함수 이름 으로 시작 합 니 다.예 를 들 면:
// Compile parses a regular expression and returns, if successful,

// a Regexp that can be used to match against text.

func Compile(str string) (*Regexp, error) {

3. 가방 이름 은 최대한 간결 하고 의미 가 있 으 며 보통 소문 자 단어 로 밑줄 이나 낙타 봉 의 이름 이 필요 하지 않 습 니 다.유닛 테스트 를 간소화 하기 위해 서가 아니라면 포인트 로 가방 을 들 여 오지 마 세 요.
4. Go 는 getters 와 setters 방법 을 제공 하지 않 고 사용자 가 스스로 실현 해 야 합 니 다.예 를 들 어 owner (소문 자, 내 보 내기 변수 가 아 닌) 라 는 필드 가 있 으 면 getter 방법 은 GetOwner 가 아 닌 Owner 라 고 명명 해 야 합 니 다.setter 방법 이 필요 하 다 면 SetOwner 라 고 명명 해 야 합 니 다.예 를 들 면:
owner := obj.Owner()

if owner != user {

    obj.SetOwner(user)

}

5. 인터페이스 이름 은 방법 이름 뒤에 er 를 추가 합 니 다. 예 를 들 어 Reader, Writer, Formatter, Close Notifier 등 입 니 다.
6. 변수 이름 은 낙타 봉, 예 를 들 어 MixedCaps 나 mixedCaps 를 사용 하고 밑줄 을 치지 않 습 니 다.
7. 고 는 C 와 마찬가지 로 분점 을 문장의 끝 표시 로 하고 고 는 품사 분석 기 가 자동 으로 추가 되 며 프로그래머 가 수 동 으로 추가 하지 않 아 도 된다.품사 분석 기 에 분 호 를 추가 하 는 표 시 는 줄 끝 에 int 나 float 64 등 키워드 형식 을 만 나 거나 아래 의 특수 문자 가 나타 나 는 것 입 니 다.
break continue fallthrough return ++ -- ) }
그래서:
if i < f() {

    g()

}

괄호 '{' 를 ')' 뒤에 두 어야 합 니 다. 그렇지 않 으 면 어법 분석 기 가 자동 으로 ')' 끝 에 문법 오 류 를 일 으 킬 수 있 습 니 다. 따라서 아래 와 같이 쓸 수 없습니다.
if i < f()  // wrong!

{           // wrong!

    g()

}

8. 필요 하지 않 은 else 는 생략 할 수 있 습 니 다. 예 를 들 어:
if err := file.Chmod(0664); err != nil {

    log.Print(err)

    return err

}

9. 성명 과 재 할당:
f, err := os.Open(name)
이 문 구 는 f 와 err 를 설명 하고 다음 과 같다.
d, err := f.Stat()
d 와 err 를 설명 하 는 것 처럼 보이 지만 사실은 d 를 설명 한 것 입 니 다. err 는 다시 할당 합 니 다. 즉, f. stat 는 위 에 존재 하 는 err 를 사 용 했 습 니 다. 이 err 에 새 값 을 다시 부여 한 것 입 니 다.
그래서 v: = declaration 이 성명 인지 재 할당 인지 에 따라 달라 집 니 다.
1. 이 성명 의 역할 영역 에 이미 설 명 된 v 가 존재 합 니 다. 그러면 할당 입 니 다. (v 가 외부 역할 영역 에 있 으 면 새로운 변수 v 를 다시 생 성 합 니 다)
예 를 들 면:
package main

 

import (

"errors"

"fmt"

)

 

func main() {

fmt.Println(declareTest())

}

 

func declareTest() (err error){

//declare a new variable err in if statement

if err := hello(); err != nil {

fmt.Println(err)

}

fmt.Println(err)

return

}

 

func hello() error {

return errors.New("hello world")

}

프로그램 출력:
hello world
 
2. 할당 이 라면 왼쪽 에 적어도 하나의 성명 의 새로운 변수 가 있어 야 합 니 다. 그렇지 않 으 면 문법 오 류 를 보고 할 수 있 습 니 다.
10. for 순환. Go 의 for 순환 은 C 와 비슷 하지만 while 순환 은 지원 되 지 않 습 니 다. 다음 세 가지 형식 이 있 습 니 다.
// Like a C for

for init; condition; post { }

 

// Like a C while

for condition { }

 

// Like a C for(;;)

for { }

배열, 절편, 문자열, map, 또는 채널 을 반복 해서 읽 을 수도 있 습 니 다. 예 를 들 어:
for key, value := range oldMap {

    newMap[key] = value

}

for pos, char := range "iam   " {

fmt.Printf("character %#U start at byte position %d
", char, pos) }

프로그램 출력:
character U+0069 'i' start at byte position 0

character U+0061 'a' start at byte position 1

character U+006D 'm' start at byte position 2

character U+4E2D ' ' start at byte position 3

character U+56FD ' ' start at byte position 6

character U+4EBA ' ' start at byte position 9

/ / Reverse a, 반전 문자 절편 a
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {

    a[i], a[j] = a[j], a[i]

} 

11. switch. Go 의 switch 는 C 보다 유연 합 니 다. case 의 표현 식 은 상수 나 정수 가 필요 하지 않 습 니 다. 예 를 들 어:
func unhex(c byte) byte {

    switch {

    case '0' <= c && c <= '9':

        return c - '0'

    case 'a' <= c && c <= 'f':

        return c - 'a' + 10

    case 'A' <= c && c <= 'F':

        return c - 'A' + 10

    }

    return 0

}

모든 케이스 는 다음 케이스 로 자동 으로 지연 되 지 않 습 니 다. 순연 이 필요 하 다 면 수 동 fall through 가 필요 합 니 다.
Switch 는 유형 판단 에 사 용 됩 니 다.
var t interface{}

t = functionOfSomeType()

switch t := t.(type) {

default:

    fmt.Printf("unexpected type %T
", t) // %T prints whatever type t has case bool: fmt.Printf("boolean %t
", t) // t has type bool case int: fmt.Printf("integer %d
", t) // t has type int case *bool: fmt.Printf("pointer to boolean %t
", *t) // t has type *bool case *int: fmt.Printf("pointer to integer %d
", *t) // t has type *int }

12. 이름 함수 반환 값 입 니 다. Go 함수 의 반환 값 은 입력 함수 처럼 명명 할 수 있 습 니 다. (물론 이름 을 바 꾸 지 않 아 도 됩 니 다) 이름 반환 값 은 함수 가 시 작 될 때 이미 형식의 0 값 으로 초기 화 되 었 습 니 다. 만약 함수 가 return 을 실행 할 때 반환 값 이 없 으 면 이름 함수 의 현재 값 이 반 환 됩 니 다. 예 를 들 어:
func ReadFull(r Reader, buf []byte) (n int, err error) {

    for len(buf) > 0 && err == nil {

        var nr int

        nr, err = r.Read(buf)

        n += nr

        buf = buf[nr:]

    }

    return

}

13. defer 로 자원 을 방출 합 니 다. 예 를 들 어 파일 을 닫 고 자 물 쇠 를 방출 합 니 다. 이렇게 하면 두 가지 장점 이 있 습 니 다. 하 나 는 자원 을 방출 하 는 것 을 잊 지 않도록 하 는 것 입 니 다. 다른 하 나 는 방출 된 코드 가 신청 한 코드 와 가 까 워 더욱 명확 합 니 다. 더 많은 defer 특성 은 제 'Golang 효율 적 인 실천 의 defer, panic, recover 실천' 박문 을 참고 하 십시오.
14. new (T) 는 0 값 이 부 여 된 메모 리 를 가리 키 는 * T 형식 을 할당 합 니 다. 예 를 들 어:
type SyncedBuffer struct {

    lock    sync.Mutex

    buffer  bytes.Buffer

}

p := new(SyncedBuffer)  // type *SyncedBuffer,   p:= &SyncedBuffer{}

var v SyncedBuffer      // type  SyncedBuffer 

15. 구조 함수. Go 는 C + + 처럼 모든 유형 에 기본 적 인 구조 함 수 를 제공 하지 않 습 니 다. 따라서 new (T) 가 할당 한 0 값 이 우리 의 요 구 를 만족 시 키 지 못 할 때, 우 리 는 구조 함 수 를 초기 화 해 야 합 니 다. 일반적으로 NewXXX 라 고 명명 합 니 다. 예 를 들 어:
func NewFile(fd int, name string) *File {

    if fd < 0 {

        return nil

    }

    f := new(File)

    f.fd = fd

    f.name = name

    f.dirinfo = nil

    f.nepipe = 0

    return f

}

이렇게 순서대로 멤버 를 초기 화 할 수도 있다.
return &File{fd, name, nil, 0}
멤버 초기 화 지정 가능:
return &File{fd: fd, name: name}
그래서 new (File) 는 & File {} 과 같 습 니 다.
16. make (T, args) 로 절편, map, channel 을 만 들 고 초기 화 된 (0 이 아 닌) T 형식 (* T 가 아 님) 을 되 돌려 줍 니 다. 이 세 가지 데이터 구 조 는 사용 하기 전에 초기 화 를 완료 해 야 하기 때 문 입 니 다. 예 를 들 어 절편 의 0 값 은 nil 이 고 nil 을 직접 조작 하면 panic 이 됩 니 다.
make([]int, 10, 100)
length 10, capacity 100 의 절편 을 할당 합 니 다. new ([] int) 가 되 돌아 오 는 값 은 0 값 (nil) 을 실행 하 는 절편 지침 입 니 다.
다음 예제 에 서 는 new 와 make 의 차 이 를 분명하게 구분 할 수 있 습 니 다.
var p *[]int = new([]int)       // allocates slice structure; *p == nil; rarely useful

var v  []int = make([]int, 100) // the slice v now refers to a new array of 100 ints

 

// Unnecessarily complex:

var p *[]int = new([]int)

*p = make([]int, 100, 100)

 

// Idiomatic:

v := make([]int, 100

슬라이스, map, channel 만 make 에 사용 되 고 포인터 가 아 닌 것 을 기억 하 세 요.
 
17. 배열. 절편 과 달리 배열 의 크기 는 고정 되 어 있어 서 메모리 재 할당 을 피 할 수 있 습 니 다. C 언어 배열 과 다 를 때 Go 의 배열 은 값 이 고 값 을 할당 할 때 배열 복사 가 발생 합 니 다. 배열 이 매개 변수 로 함수 에 전 달 될 때 함 수 는 배열 의 포인터 가 아 닌 배열 의 복사 가 받 아들 여 집 니 다. 또한 배열 의 크기 도 데이터 형식의 일부분 입 니 다.[10] int 와 [20] int 는 같은 유형 이 아니 라 고 합 니 다.
그러나 값 속성 자 체 는 효율 이 비교적 낮 습 니 다. 복사 하여 전달 하지 못 하면 배열 의 지침 을 전달 할 수 있 습 니 다. 예 를 들 어:
func Sum(a *[3]float64) (sum float64) {

    for _, v := range *a {

        sum += v

    }

    return

}

 

array := [...]float64{7.0, 8.5, 9.1}

x := Sum(&array)  // Note the explicit address-of operator

그러나 이 는 Go 의 프로 그래 밍 습관 에 맞지 않 습 니 다. 여 기 는 슬라이스 로 복사 전달 을 피 할 수 있 습 니 다.
 
18. 절편. 가능 한 한 절편 으로 배열 을 대체 합 니 다. 절편 의 본질은 배열 의 인용 입 니 다. 바 텀 데이터 구조 입 니까? 아니면 배열 입 니까? 따라서 절편 A 를 절편 B 에 할당 할 때 A 와 B 는 같은 바 텀 배열 을 가리 키 고 있 습 니 다. 함수 에 절편 을 전달 할 때 바 텀 배열 의 지침 을 전달 하 는 것 과 같 습 니 다. 따라서 절편 은 일반적으로 더욱 효율 적 이 고 자주 사용 합 니 다.
 
특히 주의해 야 할 것 은 절편 의 capacity, 즉 cap 함수 의 반환 값 은 바 텀 배열 의 최대 길이 입 니 다. 절편 이 변경 값 을 초과 하면 재 분 배 를 촉발 하고 바 텀 배열 은 확장 되 며 이전 값 을 새 메모리 에 복사 합 니 다.
 

func Append(slice, data []byte) []byte {

    l := len(slice)

    if l + len(data) > cap(slice) {  // reallocate

        // Allocate double what's needed, for future growth.

        newSlice := make([]byte, (l+len(data))*2)

        // The copy function is predeclared and works for any slice type.

        copy(newSlice, slice)

        slice = newSlice

    }

    slice = slice[0:l+len(data)]

    copy(slice[l:], data)

    return slice

}

Append 함 수 는 마지막 으로 절편 의 값 을 되 돌려 야 합 니 다. 절편 (실행 할 때 포인터, length, capacity 의 데이터 구조) 자체 가 값 으로 전달 되 기 때 문 입 니 다.
 
19. 2 차원 절편. Go 의 배열 과 절편 은 모두 1 차원 입 니 다. 2 차원 배열 이나 절편 을 만 들 려 면 배열 의 배열 이나 절편 을 정의 해 야 합 니 다. 예 를 들 어:
type Transform [3][3]float64  // A 3x3 array, really an array of arrays.

type LinesOfText [][]byte     // A slice of byte slices.

절편 의 길 이 는 가 변 적 이기 때문에 각 절편 요 소 는 길이 가 다 를 수 있 기 때문에 다음 과 같다.
text := LinesOfText{

[]byte("Now is the time"),

[]byte("for all good gophers"),

[]byte("to bring some fun to the party."),

}

주의해 야 할 것 은 make 는 1 차원 만 초기 화 할 수 있 습 니 다. 2 차원 절편 은 우리 가 수 동 으로 초기 화 해 야 합 니 다. 예 를 들 어:
// Allocate the top-level slice.

picture := make([][]uint8, YSize) // One row per unit of y.

// Loop over the rows, allocating the slice for each row.

for i := range picture {

  picture[i] = make([]uint8, XSize)

}

 
20. map. map 의 key 는 int, float, complex, 문자열, 포인터, interface (concrete type 지원 이 같다 면), 구조 체 와 배열 을 임의로 정의 할 수 있 습 니 다. 절편 은 map 의 key 로 할 수 없습니다. 절편 이 같 기 때문에 정의 되 지 않 습 니 다.
map 는 k - v 방식 으로 초기 화 할 수 있 습 니 다. 예 를 들 어:
var timeZone = map[string]int{

    "UTC":  0*60*60,

    "EST": -5*60*60,

    "CST": -6*60*60,

    "MST": -7*60*60,

    "PST": -8*60*60,

} 

key 색인 value:
offset := timeZone["EST"]
key 가 존재 하지 않 을 때 value 에 대응 하 는 0 값 을 되 돌려 줍 니 다. 예 를 들 어:
tm := make(map[string]bool)
fmt.Println(tm["test"])
false 를 출력 합 니 다. 키 가 존재 하지 않 는 지, 키 가 존재 하 는 지, 그 자체 의 value 가 0 값 인지 어떻게 구분 합 니까? "coma, ok" 문법 을 사용 할 수 있 습 니 다.
var seconds int

var ok bool

seconds, ok = timeZone[tz]

키 가 존재 할 때 ok 은 true 이 고, seconds 는 대응 하 는 value 입 니 다. 그렇지 않 으 면 ok 은 false 이 고, seconds 는 대응 하 는 value 의 0 값 입 니 다. 
delete 가 지정 한 map 의 key 로 요 소 를 삭제 할 수 있 습 니 다:
delete(timeZone, "PDT")  // Now on Standard Time
 
21. Go 의 형식 출력 은 C 언어 스타일 이지 만 C 의 printf 보다 더 고 급 스 럽 습 니 다. 모든 형식 출력 과 관련 된 함 수 는 fmt 패키지 에 있 습 니 다. 예 를 들 어 fmt. Printf, fmt. Fprintf, fmt. Sprintf 등 입 니 다. 예 를 들 어:
fmt.Printf("Hello %d
", 23) fmt.Fprint(os.Stdout, "Hello ", 23, "
") fmt.Println("Hello", 23) fmt.Println(fmt.Sprint("Hello ", 23))

% v 출력 임 의 값:
fmt.Printf("%v", timeZone)  // or just fmt.Println(timeZone)
프로그램 결과:
map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200]
 
또 예 를 들 면:
type T struct {

    a int

    b float64

    c string

}

t := &T{ 7, -2.35, "abc\tdef" }

fmt.Printf("%v
", t) fmt.Printf("%+v
", t) fmt.Printf("%#v
", t) fmt.Printf("%#v
", timeZone)

프로그램 출력:
&{7 -2.35 abc   def}

&{a:7 b:-2.35 c:abc     def}

&main.T{a:7, b:-2.35, c:"abc\tdef"}

map[string]int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}

% T 출력 형식:
fmt.Printf("%T", timeZone)
실행 결과:
map[string]int
 
% s 호출 형식의 String () 방법 으로 출력 하기 때문에 사용자 정의 형식의 String () 방법 에서% s 를 사용 할 수 없습니다. 그렇지 않 으 면 순환 이 끊 깁 니 다.
type MyString string

func (m MyString) String() string {

    return fmt.Sprintf("MyString=%s", m) // Error: will recur forever.

}

수정 버 전:
type MyString string

func (m MyString) String() string {

    return fmt.Sprintf("MyString=%s", string(m)) // OK: note conversion.

}

22. append. append 내 건 함수 정의:
func append(slice []T, elements ...T) []T

T 는 자리 표시 자 를 표시 합 니 다. 임의의 형식 일 수 있 습 니 다. 컴 파일 할 때 컴 파일 러 에서 실제 형식 으로 대 체 됩 니 다. 용법:
x := []int{1,2,3}

x = append(x, 4, 5, 6)

fmt.Println(x)

프로그램 출력: [1, 2, 3, 4, 5, 6]. 
한 개의 슬라이스 를 다른 슬라이스 끝 에 추가 하려 면 어떻게 해 야 합 니까? 예 를 들 어... 문법 을 사용 할 수 있 습 니 다. 예 를 들 어:
x := []int{1,2,3}

y := []int{4,5,6}

x = append(x, y...)

fmt.Println(x)

만약... 이 없다 면 컴 파일 은 통과 되 지 않 을 것 입 니 다. y 는 int 형식 이 아니 기 때 문 입 니 다.
총결산
본 고 는 22 개의 Golang 의 효율 적 인 실천 건 의 를 소 개 했 는데 그 중에서 프로 그래 밍 규범 과 실천 생산 에서 쉽게 만 날 수 있 는 구 덩이 를 포함 하여 여러분 에 게 도움 이 되 기 를 바 랍 니 다.
인용 하 다.
https://golang.org/doc/effective_go.html

좋은 웹페이지 즐겨찾기