Golang 고 효율 실천 의 범 담 편
제 블 로그 이전의 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
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.