Golang学习Day3

本文介绍了Go语言中的指针操作,包括值传递和指针变量的声明与使用。接着讨论了类型定义和类型别名的区别,以及结构体的声明、初始化和结构体指针的运用。最后,文章讲解了Go语言中方法的定义和接收者类型,以及值类型和指针类型作为接收者时的不同效果。
摘要由CSDN通过智能技术生成
😋 大家好,我是YAy_17,是一枚爱好网安的小白。
本人水平有限,欢迎各位师傅指点,欢迎关注 😁,一起学习 💗 ,一起进步 ⭐ 。
⭐ 此后如竟没有炬火,我便是唯一的光。 ⭐    

(暂时停更下Golang的学习,忙着准备CTF和蓝桥杯)

Go语言中的指针

Go语言中的函数传参都是值传递,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量,传递数据使用指针,而无需拷贝数据。

类型指针不能进行偏移和运算。

Go语言中的指针操作非常简单,只需要记住两个符号&(取地址)和*(根据地址取值)

指针地址和指针类型

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行取地址操作。Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如: *int、 *int64、*string等。

指针的语法

一个指针变量指向了一个值的内存地址。(也就是我们声明了一个指针之后,可以像变量赋值一样,把一个值的内存地址放入到指针当中。)类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var _name *var_type

var_type :为指针类型 var_name :为指针变量名 *:用于指定变量是作为一个指针。

package main

import "fmt"

func main() {
    var p *int
    fmt.Printf("p: %v\n", p)
    fmt.Printf("p: %T\n", p)
    var a int = 100
    p = &a
    fmt.Printf("p: %v\n", *p)

    var str *string
    fmt.Printf("str: %v\n", str)
    fmt.Printf("str: %T\n", str)
    s := "Y4y17"
    str = &s
    fmt.Printf("str: %v\n", *str)

    var bl *bool
    fmt.Printf("bl: %v\n", bl)
    fmt.Printf("bl: %T\n", bl)
    var b bool = true
    bl = &b
    fmt.Printf("bl: %v\n", *bl)
}

输出结果为:

指向数组的指针

定义语法

var ptr [MAX]*int //表示数组里面的元素的类型是指针类型

package main

import "fmt"

func main() {
    a := [3]int{1, 2, 3}
    var p [3]*int
    fmt.Printf("p: %v\n", p)
    for i := 0; i < len(a); i++ {
        p[i] = &a[i]
        fmt.Printf("p[i]: %v\n", *p[i])
    }
}

输出结果为:

Go语言中的类型定义和类型别名

Go语言类型定义

type Newtype Type

package main
import "fmt"

func main() {
    type Myint int
    var i Myint = 100
    fmt.Printf("i: %T,%v\n", i, i)
}

输出结果如下:

i: main.Myint,100

Go语言类型别名

type Newtype=Type
package main
import "fmt"
func main() {
	type Myint = int
    var i Myint = 100
    fmt.Printf("i: %T,%v\n", i, i)
}
i: int,100

Go语言中的类型定义和类型别名的区别

  1. 类型定义相当于定义了一个全新的类型,与之前的类型不同;但是类型别名并没有定义一个新的类型,而是使用一个别名来替换之前的类型

  1. 类型别名只会在代码中存在,在编译完成之后并不会存在该别名

  1. 因为类型别名和原来的类型是一致的,所以原来类型所拥有的方法,类型别名中也可以调用,但是如果是重新定义的一个类型,那么不可以调用之前的任何方法

Go语言中的结构体

在使用结构体之前我们需要定义一个结构体类型,之后通过定义的这个结构体类型在去定义结构体变量;语法结构如下:

type struct_variable_type struct{
member definition;
member definition;
......
member definition;
}	
type:结构体定义关键字
struct_variable_type:结构体类型名称
member definition:成员定义
package main

import "fmt"

func main() {
    type person struct {
        name string
        age  int
        sex  string
    }
    var tom person
    fmt.Printf("tom: %v\n", tom)
    tom.name = "tom"
    tom.sex = "man"
    tom.age = 20
    fmt.Printf("tom: %v\n", tom)
    fmt.Printf("tom.name: %v\n", tom.name)
}

输出的结果如下:

匿名结构体

package main

import "fmt"

func main() {
    var tom struct {	//匿名结构体在定义的时候不再使用type 而是var
        name string
        age  int
        sex  string
    }
    tom.name = "tom"
    tom.sex = "man"
    tom.age = 20
    fmt.Printf("tom: %v\n", tom)
    fmt.Printf("tom.name: %v\n", tom.name)
}

结构体的初始化

package main

import "fmt"

func main() {
    type person struct {
        name, email string
        age, id     int
    }
    //第一种初始化的方法:键值对的方式
    var tom person
    tom = person{
        name:  "tom",
        email: "tom@gmail.com",
        age:   20,
        id:    111,
    }
    fmt.Printf("tom: %v\n", tom)
    //第二种初始化的方法:列表的方式
    var Y4y17 person
    Y4y17 = person{
        //这种初始化的方法,必须按照结构体成员定义的顺序进行初始化
        "Y4y17",
        "Y4y17@gmail.com",
        20,
        16,
    }
    fmt.Printf("Y4y17: %v\n", Y4y17)
    //第三种初始化的方法:支持短变量赋值
    Mary := person{
        //部分赋值也是可以的
        name: "Mary",
        id:   22,
    }
    fmt.Printf("Mary: %v\n", Mary)
}
输出结果如下:
tom: {tom tom@gmail.com 20 111}
Y4y17: {Y4y17 Y4y17@gmail.com 20 16}
Mary: {Mary  0 22}

结构体指针

package main

import (
    "fmt"
)
//普通的指针变量
func test1() {
    var name string = "Y4y17"
    var nm *string
    nm = &name
    fmt.Printf("name: %v\n", name)
    fmt.Printf("nm: %v\n", nm)
    fmt.Printf("nm: %v\n", *nm)
}
//结构体指针
func test2() {
    type person struct {
        name string
        age  int
        id   int
    }
    var p_struct *person
    //这里存在3种赋值的方式
    //第一种方式:
    p_struct = &person{
        name: "Y4y17",
        age:  20,
        id:   17,
    }
    fmt.Printf("p_struct: %v\n", *p_struct)
    //第二种方式
    var tom person = person{"tom", 20, 17}
    var p_struct1 *person
    p_struct1 = &tom
    fmt.Printf("p_struct1: %v\n", *p_struct1)
    //第三种方式:
    var p_struct2 = new(person)
    p_struct2.age = 22
    p_struct2.name = "Mary"
    fmt.Printf("p_struct2: %v\n", *p_struct2)
}

func main() {
    test2()
}
输出结构如下:
p_struct: {Y4y17 20 17}
p_struct1: {tom 20 17}
p_struct2: {Mary 22 0}

结构体作为函数的参数

package main

import "fmt"

type person struct {
    name string
    age  int
    id   int
}

func show_person(per person) {
    per.name = "Y4y17"
    per.age = 24
    per.id = 17
    fmt.Printf("per: %v\n", per)
}
func main() {
    Mary := person{
        name: "Mary",
        age:  23,
        id:   99,
    }
    fmt.Printf("Mary: %v\n", Mary)
    fmt.Printf("--------------------------\n")
    show_person(Mary)
    fmt.Printf("Mary: %v\n", Mary)
}
Mary: {Mary 23 99}
--------------------------
per: {Y4y17 24 17}
Mary: {Mary 23 99}
package main

import "fmt"

type person struct {
    name string
    age  int
    id   int
}

func show_person(per *person) {
    per.name = "Y4y17"
    per.age = 24
    per.id = 17
    fmt.Printf("per: %v\n", *per)
}
func main() {
    Mary := person{
        name: "Mary",
        age:  23,
        id:   99,
    }
    fmt.Printf("Mary: %v\n", Mary)
    fmt.Printf("--------------------------\n")
    show_person(&Mary)
    fmt.Printf("Mary: %v\n", Mary)
}
修改一下代码,使得变成传递地址的方式:
Mary: {Mary 23 99}
--------------------------
per: {Y4y17 24 17}
Mary: {Y4y17 24 17}

结构体的嵌套

package main

import "fmt"

type person struct {
    name string
    age  int
    id   int
    cat  cat	//结构体中嵌套着一个cat结构体
}

type cat struct {
    name  string
    age   int
    color string
}

func main() {
    cat := cat{
        name:  "敢敢",
        age:   1,
        color: "grey",
    }
    Y4y17 := person{
        name: "Y4y17",
        age:  23,
        id:   17,
        cat:  cat,
    }
    fmt.Printf("Y4y17: %v\n", Y4y17)
    fmt.Printf("Y4y17.cat.name: %v\n", Y4y17.cat.name)
}
Y4y17: {Y4y17 23 17 {敢敢 1 grey}}
Y4y17.cat.name: 敢敢

Go语言中的方法

go语言没有面向对象的特性,也没有类对象的概念。但是,可以使用结构体来模拟这些特性,我们都知道面向;象里面有类方法等概念。我们也可以声明一些方法,属于某个结构体。

Go语言方法的语法

Go中的方法,是一种特殊的函数,定义于struct之上(与struct关联、绑定),被称为struct的接受者(receiver)。通俗的讲,方法就是有接收者的函数。

语法格式如下:
type mytype struct{}
func (recv mytype) my_method( para) return_type {}
func (recv *mytype) my_method(para) return_type {}
mytype :定义一个结构体
recv∶接受该方法的结构体(receiver)my_method:方法名称
para :参数列表
return_type :返回值类型

从语法格式可以看出,一个方法和一个函数非常相似,多了一个接受类型。

package main

import "fmt"

type person struct {
	name string
}

func (per person) eat() {
	fmt.Printf("%v eating...\n", per.name)
}
func (per person) sleep() {
	fmt.Printf("%v sleeping...\n", per.name)
}
func main() {
	var tom person
	tom.name = "tom"
	tom.eat()
	tom.sleep()
}
package main

import "fmt"

type customer struct {
    name string
}

func (cus customer) login(name string, pwd string) bool {
    if name == "tom" && pwd == "123" {
        return true
    } else {
        return false
    }
}
func main() {
    cus := customer{
        name: "tom",
    }
    b := cus.login("tom", "123")
    fmt.Printf("b: %v\n", b)
}

Go语言方法的注意事项

  1. 方法的receiver type并非一定要是struct类型,type定义的类型别名、slice、map、channel、func类型等都可以。

  1. struct结合它的方法就等价于面向对象中的类。只不过struct可以和它的方法分开,并非一定要属于同一个文件,但必须属于同一个包。

  1. 方法有两种接收类型: (T Type)和(T *Type),它们之间有区别。

  1. 方法就是函数,所以Go中没有方法重载(overload)的说法,也就是说同一个类型中的所有方法名必须都唯一。如果receiver是一个指针类型,则会自动解除引用。

  1. 方法和type是分开的,意味着实例的行为(behavior)和数据存储(field)是分开的,但是它们通过receiver建立起关联关系。

Go语言方法接收者类型

分为值类型和指针类型

package main

import "fmt"

type customer struct {
    name string
}

//传值
func (cus customer) test1() {
    cus.name = "Y4y17"
}

//传递指针
func (cus *customer) test2() {
    cus.name = "Y4y17"
}
func main() {
    cus := customer{
        name: "tom",
    }
    cus.test1()
    fmt.Printf("cus: %v\n", cus)	//cus: {tom}
    cus.test2()
    fmt.Printf("cus: %v\n", cus)	//cus: {Y4y17}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y4y17

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值