var a int //整型类型
var b string //字符串类型
var c []float32 //声明32位浮点切片类型,表示由多个浮点类型组成
var d func() bool //返回值为布尔类型的函数变量
var e struct{
x int
}//结构体类型变量,拥有一个整型x字段
也可以使用批量格式(专为懒癌患者定制)
var{
a int
b string
c []float32
...
}
整形和浮点型变量默认值是0
字符串型变量默认值是空字符串
布尔型变量默认值是false
切片,函数,指针默认值是nil
初始化标准格式:
var hp int =100
短变量声明并初始化
var hp int //声明hp变量
hp :=10
短变量声明并初始化格式在开发中使用比较普遍。
var a int =100
var b int =200
b,a=a,b //进行交换
多重赋值时,变量的左值和右值按从左到右的顺序赋值。
应用:多重赋值在GO语言的错误处理和函数返回值中会大量的使用。
func GetData(int,int){
return 100,200
}
a,_:=GetData()
_,b :=GetData()
在上一次笔记中粗浅了解过。
基本数据类型有:整型、浮点型、布尔型、字符串、切片、指针、结构体,函数,map,通道。
切片有类似指针的便利性,但比指针更安全。
结构体是Go语言的复杂类型之一
函数类型,作用是可以对其进行赋值和获取。
map和切片是开发中的常见数据容器类型。
整型,浮点型,布尔型都很熟悉不做介绍。简单介绍后几种的一些类型。
1.字符串
1.1计算字符串长度
内建函数len(),可以用来获取切片、字符串、通道等的长度。
tip1 := “genji is a ninja”
fmt.Println(len(tip1))
程序输出16
1.2.遍历字符串-----获取每一个字符串元素
有两种方法:
(1)遍历每一个ASCII字符
theme :="start"
for i:=0;i<len(theme);i++{
fmt.Printf("ascii:%c\n",theme[i])
}
(2)按Unicode字符遍历字符串
theme :="狙击 start"
for _,s :=range theme{
fmt.Printf("Unicode: %c\n",s)
}
1.3.获取字符串的某一段字符
我们使用strings.Index()函数在字符串中搜索另一个子串,代码如下:
tracer :="死神来了, 死神bye bye"
comma :=strings.Index(tracer,",")//计算,的位置,值为12
pos :=strings.Index(tarcer[comma:],"死神")计算死神这个字符出现的位置,值为3
fmt.Println(comma,pos,tracer[comma+pos:])
结果为12 3 死神bye bye
注意:comma的结果为12,因为Go语言中文为UTF-8编码,每个中文占3个字节。
1.4.修改字符串
Go语言的字符串无法直接修改每一个字符元素,只能通过重新构造新的字符串并赋值给原来的字符串变量实现。
angel :="Heros never die"
angleBytes :=[]byte(angel)
for i:=5;i<=10;i++{
angelBytes[i]=' '
}
fmt.Println(string(angleBytes))
输出为 Heros die
总结:
- Go语言的字符串是不可变的。
- 修改字符串时,可以将字符串转换成[]byte进行修改
- []byte和string可以通过强制类型转换互换
1.5.连接字符串
Go语言和大多数语言一样,使用"+"对字符串进行连接操作。但不高效。它还可以使用类似StringBulid的方法进行高效连接。例如:
hammer :="吃我一锤"
sickle :="死吧"
//声明字节缓冲
var stringBuilder bytes.Buffer//bytes.Buffer是可以缓冲并可以往里面写入各种字节数组的
//把字符写入缓冲
stringBuilder.WriteString(hammer)
stringBulider.WriteString(sickle)
//将缓冲以字符串形式输出
fmt.Println(stringBuilder.String())//用stringBuilder.String()将缓冲转换成字符串
1.6.格式化
格式化函数写法:
fmt.Sprintf(格式化样式,参数列表)
三种不同的格式输出:
(1)
//两参数格式化,与c语言相似
var progress=2
var target=8
title :=fmt.Sprintf("已采集%d个药草,还需要完成%d个任务",progress,target)
输出:已采集2个药草,还需要完成8个任务
(2)
//按数值本身输出
pi :=3.1415926
variant=fmt.Sprintf("%v %v %v",月球基地,pi,true)
输出:月球基地,3.1415926,true
(3)
//匿名结构体声明,并赋予初值
profile :=&struct{
Name string
HP int
}
{
Name: "rat",
HP: "150",
}
fmt.Printf("使用‘%%+v’ %+v\n",profile)
输出:使用%+v, &{Name:rat HP:150}
fmt.Printf("使用'%%#v' %#v\n",profile)
输出:使用%#v &struct {Name String; HP int} {Name:rat HP:150}
fmt.Printf("使用'%%T' %T\n",profile)
输出:使用%T *struct {Name String; HP int}
常用动词及功能
动词 | 功能 |
---|---|
%v | 按本来值输出 |
%+v | 在%v基础上,对结构体字段名和值进行展开 |
%#v | 输出Go语言语法格式的值 |
%T | 输出Go语言语法格式的类型和值 |
%p | 指针,十六进制方式显示 |
%% | 显示%本体 |
2.切片
切片是一个拥有相同类型元素的可变长度的序列,能动态分配空间。声明如下:
var name []T
示例:
a :=make([]int,3)
a[0]=1
a[1]=2
a[2]=3
创建一个容量为3的整形切片,并为元素赋值。
切片还可以在其元素集合内连续地选取一段区域为新的切片,就像其名字“切片”一样,切出一块区域,形成新的切片。
如:
str :="hello world"
fmt.Println(str[6:])
输出world.
- 类型指针:允许这个指针类型的数据进行修改。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。
- 切片,由指向起始元素的原始指针、元素数量和容量组成。
Go语言的指针类型变量拥有指针的高效访问,但又不会发生指针偏移,从而避免非法修改关键性数据问题。同时,垃圾回收也比较容易对不会发生偏移的指针进行检索和回收。
注意:切片比原始指针具备更大的特性,更为安全。切片发生越界时,运行时会报出宕机,并打出堆栈,而原始指针只会崩溃。
指针地址和指针类型:
Go语言中使用"&"操作符放在变量前面对变量进行"取地址"操作。
ptr := &v //v的类型为T
v代表被取地址的变量,被取地址的v使用ptr变量进行接收,ptr的类型就为"T",称作T的指针类型。""代表指针。
取值操作,用"*"进行取值,如
value := *ptr
使用指针修改值,前面已经说过使用多重赋值的方法进行数值交换,使用指针同样可以进行数值交换。代码如下:
//交换函数
func swap(a,b,*int){
t := *a
*a = *b
*b =t
}
和c语言非常相似。而且Go语言函数中如果只是交换两个指针值的话,在主函数中是交换不成功的。如:
func swap(a,b,*int){
b,a=a,b
}
创建指针的另一种方法-----new()函数
str := new(string)//new()函数可以创建一个对应类型的指针,创建过程会分配内存
*str ="ninjia"
4.常量----恒定不变的值
定义常量:
const pi=3.1415926
const e =2.71856
或者多组一起定义
const(
pi=3.1415926
e =2.71856
)
5.枚举-----一组常量值
Go语言没有枚举类型,但是有iota可以模拟枚举
type Weapon int
const(
Arrow Weapon =iota//开始生成枚举值,初始为0,之后自动增加1枚举值
Shuriken
SniperRifle
Rifle
Blower
)
例子:用iota实现KB,MB,GB的自动递增。
package main
import (
"fmt"
)
const (
B float64 = 1 << (iota * 10)
KB
MB
GB
TB
)
func main() {
fmt.Println(KB)
}
输出1024
6.类型别名
类型别名是Go 1.9版本新功能。主要用于代码升级、迁移中类型的兼容性问题。在C/C++中,重构升级可以使用宏快速定义新的一段代码。Go语言中没有选择加入宏,而是将解决重构中最麻烦的类型名变更问题。
版本1.9之前的内建类型定义的代码是这样写的:
type byte uint8
type rune int32
版本1.9之后是这样的,这个修改就是配合类型别名进行的修改。
type byte = uint8
type rune = int32
区别类型别名和类型定义:
类型别名写法:
type TypeAlias = int //给int取别名为TypeAlias
类型定义写法:
type NewInt int //将NewInt定义为int类型
区别在于:
类型别名只是类型的一个另外的名字,比如一个孩子有英文名,有小名,本质上是同一个类型。
类型定义是定义NewInt为int类型,具备int的特性,Newint将成为一种新的类型。
上面的定义如果用代码进行类型判断如:
var a NewInt
fmt.println("a type is:%T\n",a)
var a2 TypeAlias
fmt.println("a2 type is:%T\n",a2)
输出将是:
a type is: NewInt
a2 type is: int