• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Go语言--基础语法笔记

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

###

换了工作,好久没有添加新文章了,本来是想更新到github上的,想想还是在博客里放着,感觉以前的文章都没有很仔细,都只是问题处理的记录,

以后想新加一些整理的笔记也好

### 

主要内容

2.1变量

2.2数据类型

2.3数据类型相互转换

2.4指针

2.5变量生命期

2.6字符串应用

2.7枚举

2.8类型别名

2.1变量

2.1.1 声明变量

功能:存储用户的数据

注意: 变量必须经过声明才能开始使用

变量声明格式:

  1. 标准格式

var 变量名 变量类型

以关键字var开头,后置变量类型,行尾无线分号

package main
import ("fmt")
func main() {
     var a int
     var b string
     var c []float32
     var d func() bool
     var e struct{
        x int
     }
} 
  1. 批量格式

使用var关键字 和括号

package main
import ("fmt")
func main() {
     var (
        a int
        b string
        c []float32
        d func() bool
        e struct{
            x int
        }
     )
}

  

2.1.2 初始化变量

  • 整型和浮点型变量默认值:0

  • 字符串变量的默认值空字符串

  • 布尔型默认值为bool

  • 切片、函数、指针变量的默认值为nil

1.标准格式

var 变量名 变量类型 = 表达式

var hp int = 100

2.编译器推导的类型

var hp1 = 100

标准格式基础上,省略int,编译器推导

var attack = 40
var defence = 20
var damageRate float32 = 0.17
var damage = float32(attack-defence) * damageRate
fmt.Println(damage)
// 3.4

  

3.短变量声明并初始化

hp := 100

注意:变量已经被声明过了,再次声明并赋值,使用短变量声明会编译报错

var p string
p := \'123\'
fmt.Println(p)
// 错误信息:no new variables on left side of :=(44.4)
// var p 声明了p变量, p := \'123\' 会再次声明并赋值
hp3 := 50
fmt.Println(hp3)

  

2.1.3 多个变量同时赋值

顺序:从左到右

var a int = 100
var b int = 200
​
a, b = b, a
fmt.Println(a, b) //200 100

  

2.1.4 匿名变量

匿名变量用一个"_"下滑线表示

只需要在变量声明的地方,用下划线代替即可

package main
import ("fmt")
func main() {
    a1, _ := getData()
    _, b1 := getData()
    fmt.Println(a1, b1)
}
​
type IntSlice []int
// 编写一个len方法,提供切片的长度
func (p IntSlice) Len() int { return len(p)}
// 根据提供i,j元素索引,两个元素进行比较,返回比较结果
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j]}
// 根据提供i,j元素索引,交换两个元素的值
func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i]}
​
func getData() (int, int) {
    return 200, 100
}

  

2.2 数据类型

2.2.1 整型

两种: 长度 int8 int16 int32 int64 无符号 uint8 uint16 uint32 uint64

2.2.2 浮点型

两种:float32和float64

fmt.Println("hello world")
fmt.Printf("%f\n", math.Pi)
fmt.Printf("%.2f\n", math.Pi)

  

2.2.3 布尔型

注意:go不允许将整型类型转换为布尔型, 无法参与数值运算,也无法跟其他类型进行转换

var n bool
fmt.Println( int(n) * 2 ) 
//cannot convert n (type bool) to type int

  

2.2.4 字符串

用双引号括起来的内容就是为字符串的内容

  str := "hello world string"
  ch := "中文"
  fmt.Println(str, ch)
    //hello world string 中文

  

  • 字符串转义符

    符合说明
    \r 回车
    \n 换行符
    \t 制表符
    \' 单引号
    " 双引号
    \ 双斜杠
    fmt.Println( "str := \"c:\\Go\\bin\\go.exe\" ")
    str := "c:\Go\bin\go.exe" 
    

      

  • 字符串实现基于utf-8编码

  • 定义多行字符串

const longstr = `
    第一行
    第二行
    \r\n
    。。。
    
    `
    fmt.Println(longstr)
    
    //第一行
    //第二行
    //\r\n
    //。。。
​
    const codeTemplate = ` // Generated by github.com/davyxu/cellnet/protoc-gen-msg
    // DO NOT EDIT!{{range.Protos}}
    // Source:{{.Name}} {{end}}
    
    package {{.PackageName}}
    {{if gt .TotalMessages 0}}
    import (
        "github.com/davyu/cellnet"
        "reflect"
        _ "github.com/davyxu/cellnet/codec/pb"
    )
    {{end}}
    
    func init() {
        {{range .Protos}}
        //{{.Name}}{{range .Messages}}
        cellnet.RegisterMessageMeta("pb", "{{.FullName}}")
        reflect.TypeOf((*{{.Name}})(nil)).Elem(), {{.MsgID}}) {{end}}
        {{end}}
    }
    `
    fmt.Println(codeTemplate)

  


2.2.5 字符

字符串中每一个元素都叫字符 两种: 一种为uint8类型 或是 byte类型 代表ascll码的一个字符 另一种为rune类型, 代表一个UTF-8类型,实际为int32 用于处理中文、日文等复合字符 使用fmt.Printf 中“%T”输出变量实际类型,可用于查看byte和rune类型

var a byte = \'a\'
fmt.Printf("%d %T\n", a, a)
var b rune = \'中\'
fmt.Printf("%d %T\n", b, b)
//97 uint8
//20013 int32

  

2.2.7 切片 -- 能动态分配的空间

一个拥有相同类型元素的可变长的序列

var name []T

T 代表切片元素类型, 即可以整型、浮点型、布尔型、切片、map、函数等

t := make([]int, 5)
t[0] = 1
t[1] = 2
t[3] = 3
fmt.Println(t)
//[1 2 0 3 0]
    
str1 := "hello world"
fmt.Println(str1[6:])
//world

  

2.3 转换不同的数据类型

格式:

T(表达式) 输出各数值范围

package main
​
import (
    "fmt"
    "math"
)
​
func main() {   
    fmt.Println("int8 range:", math.MinInt8, math.MaxInt8)
    fmt.Println("int16 range:", math.MinInt16, math.MaxInt16)
    fmt.Println("int32 range:", math.MinInt32, math.MaxInt32)
    fmt.Println("int64 range:", math.MinInt64, math.MaxInt64)
    int8 range: -128 127
    int16 range: -32768 32767
    int32 range: -2147483648 2147483647
    int64 range: -9223372036854775808 9223372036854775807
​
    //初始化一个32位整型值
    var a1 int32 = 1047483647
    fmt.Printf("int32: 0x%x %d\n", a1, a1)
    //nt32: 0x3e6f54ff 1047483647
    //int32 转为 int16, 发生数值截断
    b1 := int16(a1)
    fmt.Printf("a1 int16: 0x%x %d\n", b1, b1)
    //a1 int16: 0x54ff 21759
    
    //将常量保存为float32类型
    var c float32 = math.Pi
    //转为int类型,浮点数发生精度丢失
    fmt.Println(int(c))
    //3
}

  

2.4 指针

两个核心:

一种是类型指针,允许对这个指针类型的数据进行修改。 传递数据使用使用指针,而无须拷贝数据 类型指针不能进行偏移和运算

二种是切片, 由指向起始元素的原始指针、元素数量和容量组成

2.4.1 认识指针地址和指针类型

每个变量在运行时都会被内存分配一个地址,这个地址代表变量在内存中的位置 使用“&”操作符放在变量前面对变量进行“取地址”操作 格式:

     ptr := &variable   //variable的类型为T

其中v代表被取地址的变量,被取地址的variable使用ptr变量进行接收,ptr的类型为“T”,称作T的指针类型。“”代表指针

package main
​
import (
    "fmt"
    "math"
)
​
func main() {   
    var cat int = 1
    var str2 string = "banana"
    fmt.Printf("%p, %p\n", &cat, &str2)
}
    //0xc00004e0e8, 0xc0000421f0 为cat,str2取地址后的指针值

  

注意:变量、指针和地址三种的关系是:每个变量都拥有地址,指针的值就是地址

2.4.2 从指针获取指针指向的值

对变量“&”取地址操作后获得这个变量的指针,对指针使用“*”操作,就是指针取值

package main
​
import (
    "fmt"
    "math"
)
func main() {
    var house = "Malibu Point 10880, 90265"
    // 对字符串取地址,ptr1类型为*string
    ptr1 := &house
    // 打印ptr类型
    fmt.Printf("ptr1 类型:%T\n", ptr1)
    // 打印ptr指针地址
    fmt.Printf("ptr1 地址:%p\n", ptr1)
    // 对指针进行取值操作
    value := *ptr1
    // 取值后类型
    fmt.Printf("value 类型:%T\n", value)
    // value值
    fmt.Printf("value:%s\n", value)
}
// ptr1 类型:*string
// ptr1 地址:0xc000042200
// value 类型:string
// value:Malibu Point 10880, 90265

总结:

取地址“&”和取值“”是一对互补操作符,“&”取地址,"&"根据地址取出地址指向的值

1.对变量进行其地址(&)操作,可获得这个变量的指针变量

2.指针变量的值是指针地址

3.对指针变量进行取值()操作,可以获得指针变量指向的原变量的值

2.4.3 使用指针修改值

x, y := 1,2

package main
​
import (
    "fmt"
    "math"
)
​
func main() {
    //错误示例
    swap1(&x, &y)
    fmt.Println("x: ",x, "y:", y)
    //x:  1 y:  2
    //正确
    swap(&x, &y)
    fmt.Println("x: ", x, "y: ",y)
    //x:  2 y:  1
}
// 交换函数
func swap(a, b *int) {
    // 取a的指针的值,赋给临时变量t
    t := *a
    //取b指针的值,赋值给a指针指向的变量
    *a = *b
    //a指针的值赋值给b指针指向的变量
    *b = t
}
​
// 错误示例
func swap1(a, b *int) {
    b, a = a, b
}

  

2.4.5 创建指针的另一种方法--new()函数

new(类型)

str3 := new(string)
*str3 = "ninja"
fmt.Println(*str3)
fmt.Println(str3)
//ninja
//0xc000042230

2.6 字符串应用

2.6.1 计算机字符串长度 -- len()

go 语言字符串都是以UTF-8格式保存,每个中文占用3个字符

tip1 := "genji is a ninja"
fmt.Println(len(tip1))
// 16
tip2 := "忍者无敌"
fmt.Println(len(tip2))
//12
// 使用RuneCountInString()统计Uncode字符数量
fmt.Println(utf8.RuneCountInString("忍者"))

 

总结

  • ASCII字符串长度使用len()函数

  • Unicode字符串长度使用utf8.RuneCountInString()函数

 

2.6.2 遍历字符串 -- 获取每个字符串

两种写法

  1. 遍历每一ASCII字符, 使用for循环遍历

theme := "阻击 start"
​
    for i := 0; i < len(theme); i++ {
​
        fmt.Printf("ascii: %c %d\n", theme[i], theme[i])
​
    }
    // ascii: é 233
    // ascii: • 152
    // ascii: » 187
    // ascii: å 229
    // ascii: • 135
    // ascii: » 187
    // ascii:   32
    // ascii: s 115
    // ascii: t 116
    // ascii: a 97
    // ascii: r 114

  

  1. 按Unicode字符遍历字符串  

  for _, s := range theme {
​
        fmt.Printf("Unicode %c %d\n", s, s)
​
    }
​
    // Unicode 阻 38459
    // Unicode 击 20987
    // Unicode   32
    // Unicode s 115
    // Unicode t 116
    // Unicode a 97
    // Unicode r 114
    // Unicode t 116

  

总结:

  • ASCII字符串遍历直接使用下标

  • Unicode字符串遍历使用for range

2.6.3 获取字符串的某一段字符

string.Index() 在字符串中搜索另一个子串

tracer := "努力拥抱每一天,不断成长"
comma := strings.Index(tracer, "每一天")
posi := strings.Index(tracer[comma:], "成长")
​
fmt.Println(comma, posi, tracer[comma+posi:])
​
 // 12 18 成长

 

总结:

  • strings.Index:正向搜索子字符串

  • string.LastIndex: 反向搜索自字符串

搜索的起始位置可以通过切片偏移制作

2.6.4 修改字符串

go语言无法直接修改每一个字符元素,只能通过重新构造新的字符串并赋值给原来的字符串变量

angel := "Hero nerver die"
​
arrayBytes := []byte(angel)
​
for i := 5; i <= 10; i++ {
​
     arrayBytes[i] = \'-\'
​
}
​
fmt.Println(arrayBytes)
​
// [72 101 114 111 32 45 45 45 45 45 45 32 100 105 101]
​
fmt.Println(string(arrayBytes))
​
 // Hero ------ die

  

总结

  • Go语言的字符串是不可以改变的

  • 修改字符串时,可以将字符串转换为[]byte进行修改

  • []byte 和string 可以通过强制类型转换互换

 

2.6.5 连接字符串

可以使用加号“+”连接 可以使用类似于StringBuilder的机制连接,更高效

hamer := "GO GO GO"
sickle := "You Can"
​
// 声明字节缓冲
​
var stringBuilder bytes.Buffer
​
// 将字符串写入缓冲区
​
stringBuilder.WriteString(hamer)
​
stringBuilder.WriteString(sickle)
​
//将缓冲以字符串形式输出
​
fmt.Println(stringBuilder.String())
​
// GO GO GOYou Can

  

  • bytes.Buffer可以缓冲并写入各种字节数组,字符串也是一种字符串数组,使用writeString()

  • 将需要连接的字符串,通过bytes.Buffer声明缓冲stringBuilder调用WriteString()方法写入里面,

  • 再通过stringBuilder.String()方法将缓冲转换为字符串

2.6.6 格式化

写法: fmt.Sprintf(格式化样式,参数列表)

格式化样式:字符串形式,格式化动词以%开头

参数列表:多个参数以逗号分隔,个数必须与格式化中样式个数一一对应

 var progress = 2
    var target = 8
​
    // 两参数格式化
    title := fmt.Sprintf("以完成%d个任务,还差%d个就完成", progress, target)
​
    fmt.Println(title)
    // 以完成2个任务,还差8个就完成
​
    pi := math.Pi
​
    // 按数值本身格式输出
    variant := fmt.Sprintf("%v %v %v", "月球基地", pi, true)    
    fmt.Println(variant)
    // 月球基地 3.141592653589793 true
​
    profile := &struct {
        Name string
        HP   int
    }{
        Name: "stat",
        HP: 150,
    }
​
    fmt.Printf("使用\'%%+v\' %+v\n", profile)
    fmt.Printf("使用\'%%#v\' %#v\n", profile)
    fmt.Printf("使用\'%%T\' %T\n", profile)
​
    // 使用\'%+v\' &{Name:stat HP:150}
    // 使用\'%#v\' &struct { Name string; HP int }{Name:"stat", HP:150}
    // 使用\'%T\' *struct { Name string; HP int }

  

base64编码解码示例

package main
​
import (
    "fmt"
    "encoding/base64"
)
​
func main() {
​
    // 需要处理的字符串
    message := "Away from keyboard. https://golang.org/" 
​
    // 编码消息, 传入的字符串需转为字节数组,才能供这个函数使用
    encodeMessage := base64.StdEncoding.EncodeToString([]byte(message))
    // 输出编码完成的消息
    fmt.Println(encodeMessage)
    // 解码消息
    data, err := base64.StdEncoding.DecodeString(encodeMessage)
    // 出错处理
​
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(string(data))
    }
​
    // QXdheSBmcm9tIGtleWJvYXJkLiBodHRwczovL2dvbGFuZy5vcmcv
    // Away from keyboard. https://golang.org/
​
​
}

  

 

2.7 枚举

2.7.1 枚举 -- 一组常量值

  // 使用iota模拟枚举
  type Weapon int
   const (
       Arrow Weapon = iota // 开始生成枚举值,默认为0
        Shuriken
       SniperRifle
       Rifle
       Blower
   )
   // 输出所有枚举值
    fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)
   var weapon Weapon = Blower
    fmt.Println(weapon)
    // 0 1 2 3 4
    // 4

 

2.7.2 枚举--将枚举值转换为字符串

package main
import ("fmt")
​
// 声明芯片类型
type ChipType intconst (
    None ChipType = iota
    GPU
    CPU
)
​
func (c ChipType) String() string {
​
    switch c {
    case None:
        return "None"
    case GPU:
        return "GPU"
    case CPU:
    return "CPU"
​
     }
    return "N/A"
​
}
​
func main() {
    // 输出CPU的值并以整型格式显示
    fmt.Printf("%s %d", CPU, CPU)
    //CPU 2
}

 


2.8 类型别名

2.8.1 区分类型别名与类型定义

类型别名的写法:

type TypeAlias = Type

类型别名规定:

TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型

// 将NewInt定义为int类型
type NewInt int
// 将int取一个别名叫IntAlias
type IntAlias = int// 将a声明为一个NewInt类型
var alias_a NewInt
fmt.Printf("a type: %T\n", alias_a)
// a type: main.NewInt
// 将a2声明为IntAlias类型
var alias_a2 IntAlias
fmt.Printf("a2 type: %T\n", alias_a2)
 // a2 type: int 

 

2.8.2 非本地类型不能定义方法

不能为不在同一个包中声明的类型定义方法,即不能为在其他包声明的类型在本地包中定义方法

package main
​
import ("time")
​
// 2.8.2
// 定义time.Duration 的别名为MyDuration
type MyDuration = time.Duration
​
// 为MyDuration 添加一个函数
func (m MyDuration) EasySet(a String) {
    
}
​
func main() {
    
}
//# 2-base/2.2-data_type
//.\data_type.go:51:6: cannot define new methods on non-local type time.Duration
//.\data_type.go:51:31: undefined: String
//exit status 2
//Process exiting with code: 1

 


2.8.3 在结构体成员嵌入时使用别名

package main
​
import (
    "fmt"
    "reflect"
)
​
// 定义商标结构
type Brand struct {
​
}
// 为商标结构添加Show()方法
func (t Brand) Show() {
​
}
​
// 为Brand定义一个别名
type FakeBrand = Brand
// 定义车辆结构,嵌入商标结构
type  Vehicle struct {
    Brand
    FakeBrand
}
​
func main() {
​
    // 声明变量 a 为车辆类型
    var a Vehicle
    // 指定调用FakeBrand的Show
    a.FakeBrand.Show()
    // 取a的类型反射对象
    ta := reflect.TypeOf(a)
​
    // 遍历a的所有成员
    for i := 0; i < ta.NumField(); i++ {
        // ta 成员信息
        f := ta.Field(i)
        // 打印成员的字段名和类型
        fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.Name())
    }
​
    
    // FieldName: Brand, FieldType: Brand
    // FieldName: FakeBrand, FieldType: Brand
​
​
}

总结:

  • FakeBrand是Brand的一个别名,在Vehicel中嵌入FakeBrand和Brand,Vehicel的类型会以名字的方式保留在Vehicle的成员中

  • FakeBrand和Brand 都有Show()方法, 调用时必须制定调用谁的, a.FakeBrand.Show()

 

 

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Go 语言基础语法发布时间:2022-07-10
下一篇:
【Go语言】基本的语法发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap