😋 大家好,我是YAy_17,是一枚爱好网安的小白。
本人水平有限,欢迎各位师傅指点,欢迎关注 😁,一起学习 💗 ,一起进步 ⭐ 。
⭐ 此后如竟没有炬火,我便是唯一的光。 ⭐
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语言中的类型定义和类型别名的区别
类型定义相当于定义了一个全新的类型,与之前的类型不同;但是类型别名并没有定义一个新的类型,而是使用一个别名来替换之前的类型
类型别名只会在代码中存在,在编译完成之后并不会存在该别名
因为类型别名和原来的类型是一致的,所以原来类型所拥有的方法,类型别名中也可以调用,但是如果是重新定义的一个类型,那么不可以调用之前的任何方法
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语言方法的注意事项
方法的receiver type并非一定要是struct类型,type定义的类型别名、slice、map、channel、func类型等都可以。
struct结合它的方法就等价于面向对象中的类。只不过struct可以和它的方法分开,并非一定要属于同一个文件,但必须属于同一个包。
方法有两种接收类型: (T Type)和(T *Type),它们之间有区别。
方法就是函数,所以Go中没有方法重载(overload)的说法,也就是说同一个类型中的所有方法名必须都唯一。如果receiver是一个指针类型,则会自动解除引用。
方法和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}
}