golang 언어 데이터 코드의 기본 구조

개요

Go 언어의 기초를 배우기 위해 몇 가지 섹션을 사용할 것입니다.이 기사의 구조는 다음과 같습니다.

数据
    new 分配
    构造函数与复合字面
    make 分配
    数组
    切片
    二维切片
    映射
    打印
    追加
 初始化
    常量
    变量
    init 函数
数据

이 섹션에서는 Go가 변수에 메모리를 할당하는 방법과 일반적으로 사용되는 배열 및 맵 데이터 구조에 대해 설명합니다.

Go는 두 가지 할당 방법, 즉 내장 함수 new 및 make를 제공합니다.

핵심:

make는 맵, 슬라이스 및 채널에만 적용되며 포인터를 반환하지 않습니다.
명확한 포인터를 얻으려면 new를 사용하여 메모리를 할당하십시오.
new에 의해 할당 된 새
함수 형식은 다음과 같습니다. new (T)
기능 : 새로 할당 된 T 유형의 0 값에 대한 포인터를 반환합니다.

내장 함수 new는 메모리 할당에 사용되는 내장 함수이지만 다른 언어에서 같은 이름의 함수와 달리 메모리를 초기화하지 않고 메모리를 0으로 만 만듭니다.

Java와 비교하여 Go의 새로운 점은 Java가 새로운 실행 구성을 통해 객체를 초기화 할 수있는 반면 Go는 초기화 (초기 값 할당)가 불가능하며 "0 값"으로 만 설정할 수 있다는 것입니다.

즉, new (T)는 유형 T의 새 항목에 대해 0으로 된 메모리 공간을 할당하고 해당 주소를 반환합니다.이 주소는 유형 * T의 값입니다. Go 용어로는 새로 할당 된 T 유형의 0 값에 대한 포인터를 반환합니다.

이 디자인은 Java와 같은 다양한 객체에 대한 다채로운 생성자와 매개 변수가 필요하지 않습니다.

new에 의해 반환 된 메모리가 0이 되었기 때문에 더 이상 초기화 할 필요가 없으며 사용자는 new로 새 객체를 생성하기 만하면 정상적으로 작동합니다.

예 :

bytes.Buffer 的文档中提到“零值的 Buffer 就是已准备就绪的缓冲区。"
sync.Mutex 并没有显式的构造函数或 Init 方法, 而是零值的 sync.Mutex 就已经被定义为已解锁的互斥锁了。
p := new(SyncedBuffer) // type *SyncedBuffer
var v SyncedBuffer // type SyncedBuffer

위의 두 가지 방법은 메모리 공간을 할당하지만 유형이 다릅니다.

생성자 및 복합 리터럴
일부 시나리오 에서는 os 패키지의 다음 코드에 표시된 것처럼 초기화 생성자가 여전히 필요합니다.

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
}

위의 코드는 너무 장황합니다. 복합 리터럴을 사용하여 단순화 할 수 있습니다.

func NewFile(fd int, name string) *File {
    if fd < 0 {
        return nil
    }
    f := File{fd, name, nil, 0}
    return &f
}

File {fd, name, nil, 0}은 복합 리터럴입니다. 이 식은 평가 될 때마다 새 인스턴스를 만듭니다.

복합 리터럴의 필드는 순서대로 나열되어야합니다. 그러나 요소가 field : value 쌍의 형식으로 명확하게 표시되면 필드를 초기화 할 때 필드가 임의의 순서로 나타날 수 있으며 지정되지 않은 필드 값에는 0 값이 할당됩니다. 따라서 다음 형식을 사용할 수 있습니다.

return & File {fd : fd, name : name} make 내장 함수를 할당하는 형식은 다음과 같습니다. make (T, args)
특징 : 슬라이스, 맵 및 채널을 생성하는 데만 사용되며 반환 유형은 T (* T가 아님)입니다. ) 초기화 된 (0이 아닌) 값입니다.

슬라이스, 맵 및 채널은 기본적으로 참조 데이터 유형이며 사용하기 전에 초기화해야합니다. 예를 들어, 슬라이스는 (배열 내부) 데이터, 길이 및 용량에 대한 포인터를 포함하여 세 항목이있는 설명자입니다.이 세 항목이 초기화되기 전에 슬라이스는 nil입니다.

슬라이스, 맵 및 채널의 경우 make는 내부 데이터 구조를 초기화하고 사용할 값을 준비하는 데 사용됩니다.

예 : make ([] int, 10, 100)은 100 개의 int가있는 배열 공간을 할당 한 다음 길이가 10이고
용량이 100 인 슬라이스 구조 new ([] int) 를 생성 하여 배열의 처음 10 개 요소를 가리 킵니다. 새로 할당 된 0으로 된 슬라이스 구조에 대한 포인터, 즉 nil
슬라이스 값에 대한 포인터를 반환 합니다.

다음 예는 new와 make의 차이점을 보여줍니다.

var p *[]int = new([]int)       // 分配切片结构;*p == nil;基本没用
var v  []int = make([]int, 100) // 切片 v 现在引用了一个具有 100 个 int 元素的新数组
 
// 没必要的复杂:
var p *[]int = new([]int)
*p = make([]int, 100, 100)
 
// 习惯用法:
v := make([]int, 100)

요점을 다시 설명하십시오.

make는 맵, 슬라이스 및 채널에만 적용되며 포인터를 반환하지 않습니다.
명확한 포인터를 얻으려면 new를 사용하여 메모리를 할당하십시오.
배열
배열은 메모리 레이아웃을 계획 할 때 매우 유용하며 때로는 과도한 메모리 할당을 피할 수 있습니다. Go에서 배열은 주로 슬라이스 구성 요소로 사용되며 슬라이스를 구성 할 때 사용됩니다.

Go와 C의 배열 간의 주요 차이점. 이동 중 :

배열은 값입니다. 한 배열을 다른 배열에 할당하면 모든 요소가 복사됩니다.
함수에 배열을 전달하면 포인터 대신 배열의 복사본을받습니다.
배열의 크기는 유형의 일부입니다. [10] int 및 [20] int 유형이 다릅니다.
배열 값 속성은 유용하지만 비용이 많이 듭니다. C의 동작과 효율성을 원한다면 배열에 대한 포인터를 전달할 수 있습니다.

Go에서 더 익숙한 사용법은 슬라이스를 사용하는 것입니다.

Slicing
Slicing은 배열을 캡슐화하여 시퀀스 된 데이터에 대해보다 다양하고 강력하며 편리한 방법을 제공합니다.

명시 적 차원이 필요한 행렬 변환과 같은 경우를 제외하고 Go에서 대부분의 배열 프로그래밍은 슬라이싱으로 수행됩니다.

슬라이스는 기본 배열에 대한 참조를 보유합니다. 슬라이스를 다른 슬라이스에 할당하면 동일한 배열을 참조합니다. 함수가 슬라이스를 매개 변수로 전달하면 슬라이스 요소에 대한 수정 사항도 호출자에게 표시되며 이는 기본 배열에 대한 포인터를 전달하는 것으로 이해할 수 있습니다.

길이 수정 : 슬라이스가 기본 배열의 한계를 초과하지 않는 한 길이는 가변적입니다. 새 슬라이스를 생성하여 자신의 변수를 다시 가리 킵니다.

슬라이스 길이 :

len (슬라이스) 슬라이스
의 용량은 내장 함수 캡을 통해 얻을 수 있으며, 슬라이스가 얻을 수있는 최대 길이를 제공합니다. 기능은 다음과 같습니다.

캡 (슬라이스)
데이터가 용량을 초과하면 슬라이스가 재 할당됩니다. 반환 값은 결과 조각입니다.

슬라이스에 항목을 추가하는 것은 매우 일반적이므로 특별한 내장 함수 append가 있습니다.

일반적으로 append 메소드를 작성하려면 최종 반환 값을 슬라이스에 반환해야합니다. 예:

  func Append(slice, data[]byte) []byte {
    l := len(slice)
    if l + len(data) > cap(slice) {  // 重新分配
        // 为了后面的增长,需分配两份。
        newSlice := make([]byte, (l+len(data))*2)
        // copy 函数是预声明的,且可用于任何切片类型。
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:l+len(data)]
    for i, c := range data {
        slice[l+i] = c
    }
    return slice
}

위와 같이 입력 매개 변수는 슬라이스와 삽입 된 요소의 값이고 반환 값은 슬라이스이며 슬라이스의 길이가 변경됩니다.
Append는 슬라이스의 요소를 수정할 수 있지만 슬라이스 자체 (런타임 데이터 구조에는 포인터, 길이 및 용량이 포함됨)가 값으로 전달됩니다.

2 차원 슬라이스
동등한 2 차원 배열 또는 슬라이스를 생성하려면 배열의 배열 또는 슬라이스 슬라이스를 정의해야합니다. 예 :

type Transform [3] [3] float64 // 3x3 배열은 실제로 여러 배열을 포함하는 배열입니다.
type LinesOfText [] [] byte // 여러 바이트 슬라이스를 포함하는 슬라이스.
각 행에는 고유 한 길이가 있습니다.
슬라이스 길이가 가변적이므로 내부에 길이가 다른 여러 슬라이스가있을 수 있습니다.

매핑
은 키 : 값의 형태로 저장되는 Go의 데이터 구조에서 맵 구조를 구현하는 것입니다.

매핑 된 값은 다양한 유형이 될 수 있습니다.
매핑 된 키는 정수, 부동 소수점 숫자, 복소수, 문자열, 포인터, 인터페이스 등이 될 수 있습니다.

매핑 된 키 (또는 인덱스)는 정수, 부동 소수점 숫자, 복소수, 문자열, 포인터, 인터페이스 (동적 유형이 같음을 지원하는 한), 구조 및 배열과 같은 같음 연산자가 지원하는 모든 유형이 될 수 있습니다. 슬라이스는 동등성이 아직 정의되지 않았기 때문에 매핑 키로 사용할 수 없습니다. 슬라이스와 마찬가지로 매핑도 참조 유형입니다.

매핑이 매개 변수로 함수에 전달되고 매핑의 내용이 변경되면 수정 내용도 호출자에게 표시됩니다.

매핑은 일반 복합 리터럴 구문을 사용하여 구성 할 수 있으며 키-값 쌍은 JSON과 같이 쉼표로 구분됩니다.

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, } 값 얻기 :






offset : = timeZone [ "EST"]
참고 : 맵에없는 키로 값을 얻으려고하면 맵의 항목 유형에 해당하는 0 값이 반환됩니다. 예를 들어 맵에 정수가 포함 된 경우 존재하지 않는 키를 찾을 때 0을 반환합니다.

값이 있는지 확인합니다.

초, ok = timeZone [tz]
위는 일반적인 "comma ok"메서드입니다.

tz가 있으면 초에 적절한 값이 할당되고 ok는 true로 설정됩니다 .- 존재하지 않으면 초는 0으로 설정되고 ok는 false로 설정됩니다.
매핑에 항목이 있는지 여부 만 확인하고 실제 값은 신경 쓰지 않는 경우 빈 식별자 _를 사용하여 값의 일반 변수를 바꿀 수 있습니다.

_, present : = timeZone [tz]
매핑에서 항목을 삭제하려면 내장 함수 delete를 사용할 수 있습니다. 이 작업은 해당 키가지도에없는 경우에도 안전합니다.

delete (timeZone,“PDT”)
Print
Go의 서식이 지정된 인쇄 스타일은 C의 printf와 비슷하지만 더 풍부하고 다재다능합니다. 이러한 함수는 fmt 패키지에 있으며 함수 이름의 첫 글자는 모두 대문자입니다 (예 : fmt.Printf, fmt.Fprintf, fmt.Sprintf 등).

예를보십시오.

// f로 끝나는 문자열은 줄
바꿈 없이 형식화 된 문자열을 매개 변수로 전달합니다. fmt.Printf ( "hello, % v \ n", "zhang3")
fmt.Fprintf (os.Stdout, "hello, % v \ n ","zhang3 ")
str : = fmt.Sprintf ("안녕하세요, % v \ n ","zhang3 ")

// 다음은
fmt.Println (str)을 래핑합니다.
// 요소 사이에 공백이 자동으로 삽입됩니다.
fmt.Fprintln (os.Stdout, "f1", "f2", "f3")
Sprintf 사용 문자열을 구성하려면 : 문자열 함수 (Sprintf 등)는 데이터 스트림에 쓰는 대신 문자열을 반환합니다.

Fprint는 다양한 스트림에 쓰는 데 사용됩니다. fmt.Fprint와 같은 형식화 된 인쇄 함수는 io.Writer 인터페이스를 구현하는 모든 객체를 첫 번째 인수로 허용합니다 (예 : os.Stdout 및 os.Stderr).

다음은 Printf에서 지원하는 형식화 된 문자에 대한 설명입니다.
– 형식 : % d
와 같은 % d는 기호 또는 크기를 나타내는 표시를 허용하지 않습니다. 이러한 속성은 실제 유형에 따라 결정됩니다.

var x uint64 = 1 << 64-1 // x는 부호없는 정수이고 다음 int64 (x)는 적합한 정수로 변환됩니다.
fmt.Printf ( "% d % x; % d % x \ n", x, x , int64 (x), int64 (x))
가 인쇄됩니다.

18446744073709551615 ffffffffffffffff; -1 -1-
형식 : % v
% v는 실제 값으로 이해할 수 있습니다.
또한 임의의 값, 심지어 배열, 구조 및 맵을 인쇄 할 수도 있습니다.

fmt.Printf ( "% v \ n", timeZone) // 또는
출력 할 fmt.Println (timeZone) 사용 합니다.

map [CST : -21600 PST : -28800 EST : -18000 UTC : 0 MST : -25200]
% + v 및 % # v
구조를 인쇄 할 때 % + v 형식은 각 필드의 필드 이름을 가져옵니다. % # v 형식은 유형을 전달합니다.

type T struct { a int b float64 c string } t : = & T {7, -2.35, "abc \ tdef"} fmt.Printf ( "% v \ n", t) fmt.Printf ( "% + v \ n ", t) fmt.Printf ("% # v \ n ", t)将 打印








& {7 -2.35 abc def} //
& {a : 7 b : -2.35 c : abc def} // 필드 이름이
& main.T {a : 7, b : -2.35, c 인 앰퍼샌드에주의하십시오. : "Abc \ tdef"} // with type
-format : % q
string 또는 [] byte 값을 만나면 % q를 사용하여 인용 된 문자열을 생성 할 수 있으며 % # q 형식은 가능한 한 많이 백틱을 사용합니다. .

– 형식 : % x
% x는 문자열, 바이트 배열 및 정수에도 사용할 수 있으며 매우 긴 16 진수 문자열을 생성 할 수 있으며 공백 (% x)이있는 형식은 바이트 사이에도 공백을 삽입합니다. .

-형식 : % T
특정 값의 종류를 인쇄합니다.

fmt.Printf ( "% T \ n", timeZone)
이 인쇄됩니다.

map [string]
int-구조 다이어그램에 대한 출력
사용자 지정 Java의 toString ()과 유사하게 구조 다이어그램 사용자 지정 형식의 기본 형식에 대해 형식에 대한 String () 문자열 서명을 사용하여 메서드를 정의하기 만하면 됩니다. 간단한 유형 T의 경우 다음 작업을 수행 할 수 있습니다.

func (t *T) String() string {
        return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}
 
fmt.Printf("%v\n", t)
会打印出如下格式:

7/-2.35/"abc\tdef"
-- 任意数量的
Printf 的签名为其最后的实参使用了 ...interface{} 类型,这样格式的后面就能出现任意数量,任意类型的形参了。

func Printf(format string, v ...interface{}) (n int, err error) {
在 Printf 函数的实现中,v 看起来更像是 []interface{} 类型的变量,但如果将它传递到另一个变参函数中,它就像是常规实参列表了。实际上,它直接将其实参传递给 fmt.Sprintln 进行实际的格式化。
// Println 通过 fmt.Println 的方式将日志打印到标准记录器。
func Println(v ...interface{}) {
    std.Output(2, fmt.Sprintln(v...))  // Output 接受形参 (int, string)
}

위의 ... interface {} 및 v ... 작성에주의하십시오.

추가 (추가 기능 설명) 추가 기능
의 시그니처는 다음과 같습니다.

func append(slice []T, 元素 ...T) []T

T는 주어진 유형의 자리 표시 자입니다. 실제로 호출자가 유형 T를 결정하는 함수를 작성할 수 없습니다. 이것이 append가 내장 함수 인 이유입니다. 컴파일러의 지원이 필요합니다.
append는 슬라이스 끝에 요소를 추가하고 결과를 반환합니다. 기본 배열이 변경 될 수 있기 때문에 결과를 반환해야합니다 (배열의 길이는 유형의 일부입니다).

以下简单的例子

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 유형이 아니므로 유형 오류로 인해 컴파일에 실패합니다. 세 개의 점 기호 "..."의 기능은 "확장"기능과 비슷합니다. 즉, y 슬라이스의 요소가 여기에 놓입니다.


GO를 초기화 하는 huaGo 의 초기화 는 매우 강력하며 초기화 과정에서 복잡한 구조를 구축 할 수있을뿐만 아니라 서로 다른 패키지 객체 간의 초기화 순서를 올바르게 처리 할 수 ​​있습니다.

상수
상수는 함수에 정의 된 지역 변수가 동일하더라도 컴파일 타임에 생성됩니다.
상수는 숫자, 문자 (룬), 문자열 또는 부울 값만 될 수 있습니다.

컴파일 시간 제한으로 인해이를 정의하는 식은 컴파일러에서 평가할 수있는 상수 식이어야합니다. 예를 들어, 1 << 3은 상수 표현식입니다.

열거 상수
열거 상수는 열거 자 iota를 사용하여 생성됩니다. iota는 식의 일부가 될 수 있고 식은 암시 적으로 반복 될 수 있으므로 복잡한 값 집합을 구성하는 것이 더 쉽습니다.

  type ByteSize float64
 
  const (
      // 通过赋予空白标识符来忽略第一个值
      _           = iota // ignore first value by assigning to blank identifier
      KB ByteSize = 1 << (10 * iota)
      MB
      GB
      TB
      PB
      EB
      ZB
      YB
  )

변수
변수 초기화는 상수와 유사하지만 초기 값은 런타임에 계산되는 일반 표현식 일 수도 있습니다.

var (
    home   = os.Getenv("HOME")
    user   = os.Getenv("USER")
    gopath = os.Getenv("GOPATH")
)

init 함수
각 소스 파일은 고유 한 매개 변수없는 init 함수를 정의하여 필요한 상태를 설정할 수 있습니다. 형식은 다음과 같습니다.

func init() { 
    ...
 }

init 메소드 실행이 끝났다는 것은 초기화가 끝났음을 의미합니다. init는 패키지의 모든 변수 선언이 초기화 프로그램에 의해 평가 된 후에 만 ​​호출되고 해당 init는 가져온 모든 패키지가 초기화 된 후에 만 ​​호출됩니다. 평가됩니다.

init 함수는 실제로 실행을 시작하기 전에 프로그램의 상태를 확인하거나 수정하는 데 자주 사용됩니다. 예:

  func init() {
    if user == "" {
        log.Fatal("$USER not set")
    }
    if home == "" {
        home = "/home/" + user
    }
    if gopath == "" {
        gopath = home + "/go"
    }
    // gopath 可通过命令行中的 --gopath 标记覆盖掉。
    flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")
  }

지금까지

위와 같이 go 언어 개발의 프로젝트 구조를 보완합니다.

cd  $GOPATH/src/github.com/goincation/code/chapter2

- sample
	- data
		data.json		-- 包含一组数据源
	- matchers
		rss.go			-- 搜索rss源的匹配器
	- search 
		default.go	-- 搜索数据用的默认匹配器
		feed.go		-- 用于读取json数据文件
		match.go		-- 用于支持不同匹配器的接口
		search.go	-- 执行搜索的主控制逻辑
	main.go 			-- 程序的入口
		

이 기사는 https://blog.csdn.net/vir56k/article/details/105113310 에서 재현됩니다.

따라서 초보자가 go 언어를 배우려면 공식 빠른 학습 문서가 권장됩니다.

https://tour.golang.org/welcome/2
마음에 드는 것이 있으면 확인해보실 수 있습니다. 개인적으로는 선배 상사라고 생각하고 내용도 매우 풍부하고 초보자에게 귀중한 의견을 많이 내놓았습니다. 동시에 IT 업계의 동료와 거물들이 많은 조언을 해주셨 으면합니다.

추천

출처blog.csdn.net/MatChen/article/details/111033580