언어 구조의 기초를 이동

이동 언어는 상속과 기타 객체 지향 개념의 "클래스"를 지원하지 않습니다 "클래스"의 개념이 없습니다. 의 인터페이스 언어와 결합 이동 포함 된 구조를 통해 확장 성 및 유연성이보다 높은 객체 지향.

유형 별칭 및 사용자 정의 유형

사용자 정의 유형

이러한 이동 언어와 같은 몇 가지 기본 데이터 유형이 있습니다 string, 整型, 浮点型, 布尔및 기타 데이터 유형, 당신은 이동의 언어 사용할 수있는 type사용자 정의 유형을 정의하는 키워드를.

사용자 정의 유형은 새로운 유형을 정의하는 것입니다. 우리는 내장 된 기본 유형도 구조체로 정의 할 수 있습니다에 따라 정의 할 수 있습니다. 예를 들면 :

//将MyInt定义为int类型
type MyInt int

하여 Type키워드의 정의 MyInt가있는 새로운 유형의 int속성을.

유형 별칭

유형 별칭은 Go1.9새 버전의 기능이 추가.

별명 조항을 입력 TypeAlias는 본질적으로 별칭을 입력 TypeAlias ​​및 유형은 동일한 유형입니다. 아이처럼 아이의 별명, 애완 동물 이름, 학교, 영어 교사와 그에게 영어 이름을 부여하기위한 과학적인 이름을 가지고 있지만 이들 이름은 모두 개인적으로 그에게 참조하십시오.

type TypeAlias = Type

우리는 전에 본 적이 rune, 그리고 byte다음과 같이가 정의 된 유형의 별칭입니다 :

type byte = uint8
type rune = int32

타입 정의 및 종류 별명 차이점

유형 별칭 유형 정의가 등호의 표면 사이의 유일한 차이점입니다, 우리는 코드를 따라 그들 사이의 차이를 이해한다.

//类型定义
type NewInt int

//类型别名
type MyInt = int

func main() {
    var a NewInt
    var b MyInt
    
    fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
    fmt.Printf("type of b:%T\n", b) //type of b:int
}

결과는 형태가 것을 보여 main.NewInt주 패키지의 정의를 보여주는 NewInt타입. B 형이다 int. MyInt이 컴파일되지 않을 때 코드를 입력에만 존재합니다 MyInt유형.

구조

데이터 유형은 몇 가지 기본 속성의 언어로 표현 될 수있는 기본 이동,하지만 우리는 사물의 재산의 전부 또는 일부를 표현하고자 할 때, 다음 하나의 기본 데이터 유형 분명히이 시간이 수요를 충족 할 수없는 언어가 제공 이동 사용자 정의 데이터 형식의 종류,이 구조, 영어 이름이라는 기본 데이터 유형, 데이터 유형의 복수를 캡슐화 할 수 있습니다 struct. 즉, 우리는 수 struct의 자신의 유형을 정의합니다.

언어를 통해 이동 struct객체 지향 구현.

구조의 정의

사용 type하고 struct다음과 같은 구조를 정의하는 키워드, 특정 코드의 형식은 다음과 같습니다

type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …
}

장소 :

  • 유형 이름 : 사용자 정의 구조의 이름을 식별, 같은 패키지에서 반복 할 수 없습니다.
  • 필드 이름 : 구조 필드 이름을 나타냅니다. 구조체 필드 이름은 고유해야합니다.
  • 필드 형식 : 필드의 특정 구조의 유형을 나타냅니다.

예를 들어, 정의는 Person다음과 같이, (인간) 구조체를 :

type person struct {
    name string
    city string
    age  int8
}

필드의 동일한 유형은, 한 줄에 쓸 수 있습니다

type person1 struct {
    name, city string
    age        int8
}

그래서 우리는이 person가있다, 사용자 정의 유형을 name, city, age세 개의 필드는 각각 도시와 연령의 이름을 지정합니다. 우리는이 사용 person구조를 쉽게 표현하고 프로그램의 개인 정보를 저장할 수 있습니다.

기본 데이터 형식을 설명하는 데 사용되는 언어로 내장하는 값이며, 구조 값의 세트를 설명하는 데 사용된다. 예를 들어, 사람은 본질적으로 데이터의 고분자 타입, 이름, 나이, 거주 도시 등이있다

구조로서는

구조가 인스턴스화 될 때에 만, 실제로 메모리를 할당합니다. 즉, 필드 구조를 사용하기 위해 인스턴스화해야합니다.

자체, 우리는 선언과 같은 내장 유형을 사용할 수 있습니다 구조의 유형 var구조 유형을 선언하는 키워드.

var 结构体实例 结构体类型

기본 인스턴스

예를 들면 :

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p1 person
    p1.name = "沙河娜扎"
    p1.city = "北京"
    p1.age = 18
    fmt.Printf("p1=%v\n", p1)  //p1={沙河娜扎 北京 18}
    fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"沙河娜扎", city:"北京", age:18}
}

우리 .필드 (멤버 변수)는 예를 들어 구조를 액세스하기 위해 p1.name그리고 p1.age등등.

익명 구조

일부 임시 데이터 구조의 정의에서, 등은 익명 장면 구조를 사용할 수있다.

package main
     
import (
    "fmt"
)
     
func main() {
    var user struct{Name string; Age int}
    user.Name = "小王子"
    user.Age = 18
    fmt.Printf("%#v\n", user)
}

포인터 형 구조를 만듭니다

우리는 또한 사용할 수있는 new구조의 주소를 얻을 인스턴스화 키워드 구조. 다음과 같은 형식입니다 :

var p2 = new(person)
fmt.Printf("%T\n", p2)     //*main.person
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"", city:"", age:0}

결과에서 우리는이 인쇄 된 것을 볼 수 p2있는 구조의 포인터.

지원 구조가 이동 언어로 직접 포인터 참고 .멤버 액세스 구조.

var p2 = new(person)
p2.name = "小王子"
p2.age = 28
p2.city = "上海"
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"小王子", city:"上海", age:28}

인스턴스화의 주소 구조를 촬영

사용 &어드레스 동작을 페치 본체 구조는 구조의 유형에 해당 new동작의 예.

p3 := &person{}
fmt.Printf("%T\n", p3)     //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "七米"
p3.age = 30
p3.city = "成都"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"七米", city:"成都", age:30}

p3.name = "七米"사실, 바닥이다 (*p3).name = "七米", 이것은 우리가 달성 할 수 있도록하기 위해 이동 언어 문법 설탕입니다.

구조 초기화

구조의 멤버 변수는 그 유형에 대응하는 값이 제로이고, 초기화되지 않았다.

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p4 person
    fmt.Printf("p4=%#v\n", p4) //p4=main.person{name:"", city:"", age:0}
}

초기화 키 - 값 쌍을 사용하여

초기화 키 - 값의 구조를 사용할 때, 필드 구조에 대응하는 키 필드의 초기 값이 있어야한다.

p5 := person{
    name: "小王子",
    city: "北京",
    age:  18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"小王子", city:"北京", age:18}

또한, 예를 들어, 구조에 대한 포인터를 초기화 할 열쇠가 될 수 있습니다 :

p6 := &person{
    name: "小王子",
    city: "北京",
    age:  18,
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"小王子", city:"北京", age:18}

어떤 초기 값 일부 필드는 필드 쓸 수없는 경우. 이 경우, 값 필드의 초기 값은 필드 타입의 제로 값을 지정하지 않는다.

p7 := &person{
    city: "北京",
}
fmt.Printf("p7=%#v\n", p7) //p7=&main.person{name:"", city:"北京", age:0}

초기 값의 목록을 사용하여

키 작성의 값에 직접 쓰기하지 않을 때 초기화하는 구조가 초기화되고, 축약 될 수있다 :

p8 := &person{
    "沙河娜扎",
    "北京",
    28,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"沙河娜扎", city:"北京", age:28}

이 초기화 형식으로, 당신은주의를 지불해야합니다 :

  1. 모든 필드는 구조를 초기화해야합니다.
  2. 순서 초기 값을 채우는 것은 구조의 선언에서 필드 순서와 일치해야합니다.
  3. 방법은 혼합 키 초기화 방법은 없습니다.

메모리 레이아웃 구조

구조는 연속적인 메모리를 점유한다.

type test struct {
    a int8
    b int8
    c int8
    d int8
}
n := test{
    1, 2, 3, 4,
}
fmt.Printf("n.a %p\n", &n.a)
fmt.Printf("n.b %p\n", &n.b)
fmt.Printf("n.c %p\n", &n.c)
fmt.Printf("n.d %p\n", &n.d)

출력 :

n.a 0xc0000a0060
n.b 0xc0000a0061
n.c 0xc0000a0062
n.d 0xc0000a0063

[] 이동 언어에 대한 고급 지식 읽기 메모리 정렬을 권장 : 이동 바로 메모리에 정렬

인터뷰 질문

무엇 윌 다음 코드의 결과?

type student struct {
    name string
    age  int
}

func main() {
    m := make(map[string]*student)
    stus := []student{
        {name: "小王子", age: 18},
        {name: "娜扎", age: 23},
        {name: "大王八", age: 9000},
    }

    for _, stu := range stus {
        m[stu.name] = &stu
    }
    for k, v := range m {
        fmt.Println(k, "=>", v.name)
    }
}

생성자

우리가 실현을 소유하고, 언어의 구조는 생성자가 없습니다 이동합니다. 예를 들어,의 실현에 아래의 코드 person생성자입니다. 이 때문에 struct구조가 더 복잡하면 값 종류, 생성자 구조 유형에 대한 포인터를 리턴하도록 성능 오버 헤드의 값이 비교적 큰 것 사본.

func newPerson(name, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

생성자를 호출

p9 := newPerson("张三", "沙河", 90)
fmt.Printf("%#v\n", p9) //&main.person{name:"张三", city:"沙河", age:90}

방법 및 수신자

언어를 이동하는 方法(Method)변수 함수의 특정 유형에 대한 작업입니다. 변수의이 특별한 유형이라고 接收者(Receiver). 개념은 다른 언어에받는 사람과 유사 this또는 self.

이 방법은 다음과 같은 형식으로 정의된다 :

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
    函数体
}

그 중,

  • 받는 사람 변수 : 매개 변수 이름 공식의 수신자 명명 첫 번째 유형 소문자를받는 사람의 이름을 사용하는 것이 좋습니다 대신 self, this등을 임명했다. 예를 들어, Person변수의 유형을받는 사람 이름을 지정해야합니다 p, Connector수신기의 유형은 변수를 지정해야 c처럼.
  • 수신기 입력 : 수신기 유형과 유사한 매개 변수는 포인터와 포인터가 아닌 유형 유형이 될 수 있습니다.
  • 메소드 이름, 매개 변수 목록, 반환 매개 변수 : 함수 정의의 특정 형식과 동일합니다.

예를 들면 :

//Person 结构体
type Person struct {
    name string
    age  int8
}

//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
    return &Person{
        name: name,
        age:  age,
    }
}

//Dream Person做梦的方法
func (p Person) Dream() {
    fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}

func main() {
    p1 := NewPerson("小王子", 25)
    p1.Dream()
}

방법 및 차 함수가 방법의 특정 유형에 속하는 모든 유형의 함수가 아니다.

포인터 타입받는 사람

방법 후 변형이 효과적 방법을 호출 할 때 포인터 타입 수신기 포인터의 특성에 의한 조성물의 구조에 대한 포인터, 포인터가 어떤 수신자 부재 변수를 수정. 이 방법은 다른 객체 지향 언어이다 매우 가까이 thisself. 예를 들어, 우리는 Person추가 SetAge연령 인스턴스 변수를 수정하는 방법을.

// SetAge 设置p的年龄
// 使用指针接收者
func (p *Person) SetAge(newAge int8) {
    p.age = newAge
}

이 메소드가 호출됩니다 :

func main() {
    p1 := NewPerson("小王子", 25)
    fmt.Println(p1.age) // 25
    p1.SetAge(30)
    fmt.Println(p1.age) // 30
}

받는 사람의 값 유형

방법은받는 사람 유형의 역할을 소중히 할 때, 실행 언어 코드를 이동 할 때받는 사람의 복사본의 값입니다. 방법에서 당신은받는 사람 멤버 값의받는 사람의 유형의 가치를 얻을 수 있지만 수정 작업의 사본을받는 사람은 변수 자체를 수정할 수 없습니다.

// SetAge2 设置p的年龄
// 使用值接收者
func (p Person) SetAge2(newAge int8) {
    p.age = newAge
}

func main() {
    p1 := NewPerson("小王子", 25)
    p1.Dream()
    fmt.Println(p1.age) // 25
    p1.SetAge2(30) // (*p1).SetAge2(30)
    fmt.Println(p1.age) // 25
}

당신은 포인터 타입 수신기를 사용해야하는 경우

  1. 당신은받는 사람의 값을 수정해야
  2. 받는 사람은 상대적으로 큰 대형 개체의 비용의 복사본입니다
  3. 포인터 수신기를 사용하는 방법이 있다면 다른 방법은 포인터받는 사람을 사용해야하므로, 일관성을 확인합니다.

방법의 모든 유형을 추가

이동 언어에서,받는 사람뿐만 아니라 모든 유형 구조 될 수 있습니다 입력 방법의 모든 유형을 가질 수 있습니다. 예를 들어, 우리는에 따라 내장 int새로운 사용자 정의 유형을 정의하고 우리의 사용자 지정 형식에 메서드를 추가 할 수있는 형식 키워드 형태의 사용.

//MyInt 将int定义为自定义MyInt类型
type MyInt int

//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
    fmt.Println("Hello, 我是一个int。")
}
func main() {
    var m1 MyInt
    m1.SayHello() //Hello, 我是一个int。
    m1 = 100
    fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt
}

주 : 비 네이티브 유형은 우리가 다른 패키지 유형 정의 방법을 제공 할 수 없음을 의미하는 방법을 정의 할 수 없습니다.

익명 필드 구조

구조는 회원이 문 만 유형에 필드 이름을 필드 수 없습니다,이 필드의 이름이 아닌 익명 필드라고합니다.

//Person 结构体Person类型
type Person struct {
    string
    int
}

func main() {
    p1 := Person{
        "小王子",
        18,
    }
    fmt.Printf("%#v\n", p1)        //main.Person{string:"北京", int:18}
    fmt.Println(p1.string, p1.int) //北京 18
}

필드 이름과 유형 이름에 대한 익명 필드의 디폴트는, 구조에 필요한 필드 이름은 고유해야하므로 필드의 같은 익명 형식의 구조는 하나를 가질 수 있습니다.

중첩 구조

구조적 본체는 중첩 구조 또는 다른 구조에 대한 포인터를 포함 할 수있다.

//Address 地址结构体
type Address struct {
    Province string
    City     string
}

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address Address
}

func main() {
    user1 := User{
        Name:   "小王子",
        Gender: "男",
        Address: Address{
            Province: "山东",
            City:     "威海",
        },
    }
    fmt.Printf("user1=%#v\n", user1)//user1=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

익명 중첩 된 구조

//Address 地址结构体
type Address struct {
    Province string
    City     string
}

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address //匿名结构体
}

func main() {
    var user2 User
    user2.Name = "小王子"
    user2.Gender = "男"
    user2.Address.Province = "山东"    //通过匿名结构体.字段名访问
    user2.City = "威海"                //直接访问匿名结构体的字段名
    fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

구조체 멤버에 액세스 할 때 우리는 먼저 익명의 구조를가는 모습을 찾을 수없는 구조에서 필드를 찾을 수 있습니다.

필드 이름이 충돌 중첩 구조

동일한 필드 이름에 존재 내부 중첩 구조. 모호성을 피하기 위해이 시간은 내장 된 구조의 특정 필드를 지정해야합니다.

//Address 地址结构体
type Address struct {
    Province   string
    City       string
    CreateTime string
}

//Email 邮箱结构体
type Email struct {
    Account    string
    CreateTime string
}

//User 用户结构体
type User struct {
    Name   string
    Gender string
    Address
    Email
}

func main() {
    var user3 User
    user3.Name = "沙河娜扎"
    user3.Gender = "男"
    // user3.CreateTime = "2019" //ambiguous selector user3.CreateTime
    user3.Address.CreateTime = "2000" //指定Address结构体中的CreateTime
    user3.Email.CreateTime = "2000"   //指定Email结构体中的CreateTime
}

구조 "상속"

구조에 사용되는 이동 언어는 다른 프로그래밍 언어, 객체 지향 상속 구현 될 수있다.

//Animal 动物
type Animal struct {
    name string
}

func (a *Animal) move() {
    fmt.Printf("%s会动!\n", a.name)
}

//Dog 狗
type Dog struct {
    Feet    int8
    *Animal //通过嵌套匿名结构体实现继承
}

func (d *Dog) wang() {
    fmt.Printf("%s会汪汪汪~\n", d.name)
}

func main() {
    d1 := &Dog{
        Feet: 4,
        Animal: &Animal{ //注意嵌套的是结构体指针
            name: "乐乐",
        },
    }
    d1.wang() //乐乐会汪汪汪~
    d1.move() //乐乐会动!
}

가시성 필드 구조

필드 구조의 시작은 공개적으로 액세스 대문자로 표시에서, 소문자는 개인 (단지 현재의 패킷 구조 정의에 액세스 할 수있다)을 나타낸다.

시퀀스 및 JSON의 구조

JSON (JavaScript Object Notation)은 경량 데이터 교환 형식입니다. 쉽게 읽고 쓸 수 있습니다. 기계가 분석하고 생성하는 것은 간단합니다. JSON 키 - 값 쌍 방법 JS 객체 키 / 값 쌍 조합 키 따옴표 사설 저장하는 데 사용되는 ""결장, 래핑을 :값으로 단락 지어진 후이어서, 복수의 사이 영 키 ,구분 .

//Student 学生
type Student struct {
    ID     int
    Gender string
    Name   string
}

//Class 班级
type Class struct {
    Title    string
    Students []*Student
}

func main() {
    c := &Class{
        Title:    "101",
        Students: make([]*Student, 0, 200),
    }
    for i := 0; i < 10; i++ {
        stu := &Student{
            Name:   fmt.Sprintf("stu%02d", i),
            Gender: "男",
            ID:     i,
        }
        c.Students = append(c.Students, stu)
    }
    //JSON序列化:结构体-->JSON格式的字符串
    data, err := json.Marshal(c)
    if err != nil {
        fmt.Println("json marshal failed")
        return
    }
    fmt.Printf("json:%s\n", data)
    //JSON反序列化:JSON格式的字符串-->结构体
    str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
    c1 := &Class{}
    err = json.Unmarshal([]byte(str), c1)
    if err != nil {
        fmt.Println("json unmarshal failed!")
        return
    }
    fmt.Printf("%#v\n", c1)
}

구조 태그 (태그)

Tag메타 정보 구조는 런타임 반사에 메커니즘에 의해 판독 할 수있다. Tag안티 랩 시세, 특히 다음과 같은 형식의 한 쌍의 필드에 상기 정의 된 구조, 후 :

`key1:"value1" key2:"value2"`

하나 이상의 키 - 값 쌍의 구조 라벨. 키와 값은 콜론, 따옴표의 값으로 구분. 쌍 사이에 구분 된 공간을 사용합니다. 참고 : 구조에 대한 서면 Tag, 우리는 엄격하게 키 - 값 쌍의 규칙을 준수해야합니다. 코드 라벨 구조를 해결하기위한 결함 허용 형식이 잘못되면, 컴파일시 에러 메시지를 표시하지 않습니다 및 런타임, 정확하지 않을 수있는 값을 반영하여, 좋지 않습니다. 예를 들어, 키와 값 사이에 공백을 추가하지 마십시오.

예를 들어, 우리는 Student구조 JSON 직렬화 태그의 각 필드의 정의를 사용합니다 :

//Student 学生
type Student struct {
    ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的key
    Gender string //json序列化是默认使用字段名作为key
    name   string //私有不能被json包访问
}

func main() {
    s1 := Student{
        ID:     1,
        Gender: "男",
        name:   "沙河娜扎",
    }
    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("json marshal failed!")
        return
    }
    fmt.Printf("json str:%s\n", data) //json str:{"id":1,"Gender":"男"}
}

연습 문제

  1. 학생 정보 관리 시스템을 준비하기 위해 생각의 "객체 지향"방법을 사용합니다.
    1. ID, 이름, 나이, 점수 및 기타 정보 학생
    2. 프로그램은 학생, 학생 및 기타 기능을, 목록을 표시 학생, 학생 정보 편집, 추가, 삭제 제공

추천

출처www.cnblogs.com/nickchen121/p/11517431.html