这里主要记载Go语言对于Java的不同用法~
文章目录
注释和转义字符
1.注释
注释快捷键:ctrl+/
2.转义字符
(1),go的字符串只能使用双引号,所以想在字符串中显示单引号,那么就得使用转义字符
fmt.Println("\"hello world\"")
(2),go支持反引号,反引号引起来的字符串不支持转义
fmt.Println(`"hello\n world"`)
//输出为:"hello\n world"
(3),单引号只能用来包裹一个字节的ASCII码字符
var a int = '中'
(4),其他转义字符
\" | 双引号 |
---|---|
\\ | 反斜线 |
\a | 报警声 |
\t | 制表符 |
\b | 退格 |
\f | 换页 |
\n | |
\v | 垂直制表符 |
3.格式化字符串
- Print -->函数直接输出内容
- Printf -->格式化输出字符串
- Println -->会在输出内容的结尾添加一个换行符
- %v -->按值的本来值输出
- %+v -->在%v基础上,对结构体字段名和值进行展开%#v输出Go语言语法格式的值
- %T -->输出Go语言语法格式的类型和值
- %% -->输出%本体%b(oOdxX)整型的不同方式显示
- %U -->Unicode字符
- %s -->字符串
- %d -->整数
- %f -->浮点数
- %p -->指针,十六进制方式显示
二,变量和常量:
1.变量
在go语言中变量的数据类型是要放在变量名后面的
(1)变量声明的格式:
①:var+变量名+数据类型+“=”+变量值(其中数据类型可以省略)
②:简写:变量名+“:=”+变量值
③:批量声明:
var(变量名1+数据类型+“=”+变量值
变量名2+数据类型+“=”+变量值
变量名3+数据类型+“=”+变量值
…
)
(2)特点
①Go语言会自动推断变量值类型,即在声明变量时可以将变量类型省略
②定义变量之后必须要使用,否则会报错。批量声明的变量可以不被使用
2.常量(Constant)
(1)常量的声明格式
①:const+常量名+数值类型+“=”+常量值
②:批量声明:
const(变量名1+数据类型+“=”+变量值
变量名2+数据类型+“=”+变量值
变量名3+数据类型+“=”+变量值
…
)
const a int=1
(2)特点
①常量在声明之后不可以被修改
②在声明时必须被赋值
(3)iota
批量声明时可以使用iota用来实现常量的计数功能,iota就是当前变量的层数(每一个括号里面会从0开始算)
3.全局变量
将变量声明在函数之外。全局变量在声明后可以不被使用
4.跨包变量
在当前项目中创建一个version目录,在version目录中创建一个.go文档
在主程序中就可以引入该包进行使用
package main
import (
"fmt"
"go_study/version"
)
func main(){
fmt.Println(version.Version)
}
如果某变量需要跨包使用,则该变量首字母需要大写
三,基本数据类型
1.字符串
bute:uint8的别名
rune:uint32的别名
字符串型的变量值要使用’ ’
2.布尔型
bool–>true/false
3.字符型
len():输出字符串的字节长度
四,运算符
1.算数运算符
+,-,*,/,%
在go中没有前++,只有后++
没有次方,"^"表示异或
2.位运算符
&按位与 全1为1
| 按位或 有1为1
^按位异或 相同为0,不同为1
“>>”:往右移两位
“<<”:往左移两位
3.赋值运算符
+= -= *= /=
4.逻辑运算符
&& 与 || 或 !非
逻辑运算符只针对布尔类型的数据值或者表达式使用
五,判断语句
1.if else
①,条件不需要加括号,但是加了之后也不会报错
②,if后面的左大括号必须和if在同一行,否则编译不通过
③,if的简短语句
在进行判断之前,可以声明变量,用于接收函数返回值并判断
if i:=3;i>8{
fmt.Println("大于0")
}
2.switch case
(1)用法:
在go中每个执行语句后面默认带有break语句,可以使用fallthrough来表示继续执行后面的代码
switch{
case 条件语句1:
执行语句1
case 条件语句2:
执行语句2
……
}
(2)与if else的区别:
if else是多个条件选一个,只要成立了一个,后面的就都不会去匹配了
switch的每一个case是从上到下去匹配,如果没有break,则每一个条件都会去匹配
六,循环语句
1.for循环
go里面没有while循环,只有for循环这一种
想要实现无限循环可以去掉for的循环条件
for语句后面的三个构成部分不能加括号,否则会报错
2.break与continue
break是结束循环(直接跳出了循环,跳出循环后不再执行循环语句),continue是跳出本次for循环,直接进行下一次的循环(结束本次循环后重新开启本次循环)。continue后面的代码就不会执行了
七,label标签与goto
Go语言支持label(标签)语法:分别是break label,goto label,continue label
1.break label:
跳出循环不再执行for循环里的代码,一般用于跳出多层循环
break label只能用于for循环,不能和switch一起使用,标签要放在break的前面
在for循环外层定义一个标签,例如:“target:”,可以直接跳出最外层的循环
start:
for i := 0; i < 6; i++ {
for j := 0; j < 8; j++ {
fmt.Print("*")
if i == 2 && j == 2 {
break start
}
}
fmt.Println()
}
输出:
********
********
***
2.continue label:
continue label和break label功能相似,区别在于breaklabel是强制终止,continue label是继续循环下一个迭代
start:
for i := 0; i < 6; i++ {
for j := 0; j < 8; j++ {
fmt.Print("*")
if i == 2 && j == 2 {
continue start
}
}
fmt.Println()
}
输出:
********
********
***********
********
********
由此可见,在三行三列这一行代码执行完毕之后,跳出循环,又来到第四行第一列的位置继续执行代码
3.goto label:
goto可以无条件的跳转执行的位置,但是不能跨函数,需要配合标签使用
goto的标签放在goto的上面和下面都可以
例:使用goto实现循环
var name string
start:
fmt.Println("请输入用户名")
fmt.Scanln(&name)
if name != "1" {
goto start
}
fmt.Println("登录成功")
}
八,指针
1.值传递和址传递:
①,值传递:例如在主函数定义一个变量name,在主函数外部定义一个setName的函数需要传递一个name参数,此时就会将传过去的name参数在内存中另外开辟一块空间进行拷贝,再将新地址中的数据传递给setName函数,此时在setName函数中修改name的值,主函数中name的值不会发生变化
②,址传递:在传参时直接将主函数中的name的地址值传给setName函数,此时setName函数和主函数中的name使用同一个地址,在setName函数中修改name的值,主函数中name的值也会发生变化
址传递的变量类型为:“*string”,如要修改name的值,应使用:name=" "
可以使用&来获取某个变量的内存地址,用获取到内存地址所对应的值
九,defer
1.延迟执行的函数会被压入栈中,return后按照先进后出的顺序调用
2.延迟执行的函数其参数会立即求值
3.可用于函数的异常捕获
十,init函数
1.init函数可以在所有程序执行开始前被调用,并且每个包下可以有多个init函数
2.init函数先于main函数自动执行
3.每个包中可以有多个init函数,每个包中的源文件中也可以有多个init函数
4.init函数没有输入参数,返回值,也未声明,所以无法引用
5.不同包的init函数按照包导入的依赖关系决定执行顺序
6.无论包被导入多少次,init 函数只会被调用一次, 也就是只执行一次
7. init 函数在代码中不能被显示的调用,不能被引用(赋值给函数变量),否则会出现编泽错误
8. Go程序仅仅想要用一个package的init执行,我们可以这样使用: import_" test xxx",导入包的时候加上下划线就ok了
9. init 函数不应该依赖任何在main函数里创建的变量,因为init函数的执行是在main函数之前的
10.执行顺序:
被依赖的全局变量> >被依赖包的init函数> >… > > main包的全局变量> > main的init函数> > main函数
十一,包
1.包的导入:import “包名”
要使用其他包内的函数,直接将包导入之后就可以用"包名+.+函数名"即可调用函数,不需要加文件名
2.需要导入的包过多时,可以简写
import{
包名1
包名2
包名3
……
}
3.起别名
如果有两个一样的包,那么在导入的时候就可以起一个别名
import{
pkg1 “demo/pkg”
pkg2 “demo/pkg”
}
起一个别名后在使用包时直接使用包的别名,如果使用包的原来名称会报错
4.全部引入
在使用包中的函数,变量时。通常是包名点变量名,如果想直接使用变量名,那么需要将包中的内容全部导入
十二,数组
1.数组的定义
var arr ([3]int) = [3] int {1,2,3}||arr :=[...]int{1,3,5,7}
简写:
var arr = [...] int {1,2,3}//(go语言可以自动推断数组长度)
十三,map
map是key-value的形式,其中key只能是基本数据类型
1,map的声明:定义并创建
func main() {
var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println("初始化元素:")
//对切片中的map元素进行初始化
mapSlice[0] = make(map[string]string)
mapSlice[0]["name"] = "小明"
mapSlice[0]["gender"] = "男"
mapSlice[0]["address"] = "中国"
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
}
简写:
m:= map[string]string{
"name":"张三",func main() {
m := make(map[string][]string)
fmt.Println(m)
val := []string{"北京", "上海"}
m["中国"] = val
fmt.Println(m)
m["中国"] = append(m["中国"], "广州", "深圳")
fmt.Println(m)
}
"age":"12",
}
2.常用方法
(1)查找
通过双赋值检测某个key是否存在
v,ok:= m2["name"]
if ok{
//如果存在ok就为true
fmt.Printf("v= %v",v)
}else{
fmt.Pringf("v不存在")
}
(2)删除
delete(map,key)//删除单个元素
要删除所有key-value,可以重新make
(3)遍历
map只有len,没有cap
len一个map,得到的就是key的个数
只有for range一种遍历方式
for key,value :=range n{
fmt.Printf("key=%v,value=%v\n",key,value)
}
3.map扩展
(1)切片中的元素为map类型
var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
//对切片中的map元素进行初始化
mapSlice[0] = make(map[string]string)
mapSlice[0]["name"] = "小明"
mapSlice[0]["gender"] = "男"
mapSlice[0]["address"] = "中国"
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
}
(2)map中的值为切片类型
func main() {
m := make(map[string][]string)
fmt.Println(m)
val := []string{"北京", "上海"}
m["中国"] = val
fmt.Println(m)
m["中国"] = append(m["中国"], "广州", "深圳")
fmt.Println(m)
}
十四,自定义数据类型和类型别名
1.自定义数据类型
type msgType uint16//–>自定义一个数据类型为uint16的新的数据类型msgType
此时msgType与uint16是属于不同的数据类型,如果要将uint16的变量赋值给msgType的变量,则需要进行类型转换
2.类型别名
byte是uint8的别名
rune是int32的别名
type msgType = uint16
类型别名就相当于是将uint16起了一个别的名字
赋值的时候也不用类型转换
十五,结构体
由一组字段构成的一种自定义数据类型
1.实例化结构体对象的方法
//创建一个结构体
type User struct {
Name string
Age int
password string
}
(1)
var u1 User = User{"张三", 22, "#256as"}
fmt.Printf("u1:%v u1的类型为:%T", u1, u1)
以这种方式进行实例化时,括号内的参数顺要和创建结构体时参数的顺序相同
(2)以传参的方式进行实例化
var u2 User = User{
Name:"李四",
password: "$11902dd",
Age: 18,
}
fmt.Printf("u2:%v u2的类型为:%T", u2, u2)
(3)声明一个结构体对象,以赋值的方式进行实例化
var u3 User
u3.Name = "王五"
u3.Age = 25
u3.password = "*22998aas"
fmt.Printf("u3:%v u2的类型为:%T", u3, u3)
2.结构体继承
type User struct {
Name string
Age int
password string
}
type Account struct {
money float32
User
}
func main() {
var ac Account = Account{
money: 21.5,
User: User{
Name: "张三",
Age: 21,
password: "*129987hhc",
},
}
fmt.Printf("ac %#v,%T\n", ac, ac)
}
type User struct {
Name string
Age int
password string
}
type Account struct {
money float32
User
}
func main() {
var u1 User = User{
Name: "张三",
Age: 21,
password: "*129987hhc",
}
var ac Account = Account{
money: 21.5,
User: u1,
}
fmt.Printf("ac %#v,%T\n", ac, ac)
}
3.结构体方法
在继承结构体时,该结构体的方法也被继承
type User struct {
Name string
Age int
password string
}
type Account struct {
money float32
User
}
func (u User) PrintName() string {
fmt.Println("printName方法:", u)
fmt.Printf("printName方法内部: %p\n", &u)
return u.Name
}
func main() {
user := User{"李四", 23, "03396aac"}
fmt.Printf("main:%p\n", &user)
name := user.PrintName() //是值传递
fmt.Println(name, user)
account := Account{
money: 234,
User: user,
}
name = account.PrintName()
fmt.Println(name)
}
4.结构体指针
如果想要修改结构体里面的值,需要使用指针
type Accounts struct {
Name string
Age int
}
// ac是拷贝的,修改无效
func (ac Accounts) setAge(age int) {
ac.Age = age
}
// ac是执行原结构体User的
func (ac *Accounts) setName(name string) {
(*ac).Name = name
}
func main() {
accounts := &Accounts{"张三", 23}
accounts.setName("李四")
accounts.setAge(12)
fmt.Println(accounts)
}
输出结果:
&{李四 23}
5.结构体标签
import (
"encoding/json"
"fmt"
)
type Article struct {
Title string `json:"title"`
UserName string `json:"-"` //-也不参与序列化
LookCount int `json:"lookCount"`
Free bool `json:"free"`
password string `json:"password"` //小写字母开头的不会参与序列化
}
func main() {
article := Article{
Title: "golang文档",
UserName: "张三",
LookCount: 1024,
Free: true,
password: "12334¥ssa",
}
//结构体转json
jsonData, err := json.Marshal(article)
if err != nil {
fmt.Println(err)
return
}
jsonStr := string(jsonData)
fmt.Println(jsonStr)
}
输出结果:
{"title":"golang文档","lookCount":1024,"free":true}
十六,接口
type Animal interface {
Sing()
Dump(time string)
Rap() string
}
type Chicken struct {
Name string
}
func (c Chicken) Sing() {
fmt.Println("调用了Sing方法")
}
func (c Chicken) Dump(time string) {
fmt.Println("调用了Dump方法")
}
func (c Chicken) Rap() string {
fmt.Println("调用了Rap方法")
return "rap"
}
func main() {
var animal Animal
animal = Chicken{"33"}
animal.Sing()
animal.Dump("2")
animal.Rap()
}
type Animal interface {
Sing()
}
type Chicken struct {
Name string
}
func (c Chicken) Sing() {
fmt.Println("chicken调用了Sing方法")
}
type Cat struct {
Name string
}
func (cat Cat) Sing() {
fmt.Println("cat调用了Sing方法")
}
func Sing(animal Animal) {
animal.Sing()
}
func main() {
chicken := Chicken{"33"}
cat := Cat{"44"}
Sing(chicken)
Sing(cat)
}