Golang基础语法

Go

1.声明变量

  1.指定变量类型 (variable)
  var  i int
  如果未指定默认值 那么默认值为0
  2.自动判断值类型 
  var  i="string";
  3.省略var 初始化声明
  hello:="spark"
  
  多变量声明
  1.指定声明变量的类型 统一类型
  var i,k,s,w int 
  2.声明不同的类型
  var (
  i int
  str string
  b bool
  )
  !!!在同一个作用域当中 不能对变量进行二次初始化 :变量名=v

2.Go语言常量

  const关键词  常量声明语法
  1.单个常量声明方法 显示声明 const 变量名 变量类型=value
  const str string  ="100"
  2.隐示声明 可省略string  因为会自动推断类型
  const str ="100"
  const str,str1 int
  3.枚举声明
  const (
  MAN=1
  GIRL=0
  )
  4.特殊常量iota 在const关键词出现时被重置为0 每次出现一次+1可以把iota当作const索引
 const (
    MAN = iota //0
    MAIN        //1
        _              //2
        afer         //3
)

3.运算符

//算术运算符
+ - * /  ++ --
//关系运算符 跟Java中的一致
== !=  > <  >= <= 
//逻辑运算符
&& || !

4.for循环

//berak关键词  停止当前循环
//goto  跳转到指定的标签
//continue  跳过当前循环
func  main()  {
    //var i="string";

    for i:=1; i<=10 ;i++  {
    //  goto  breakHader
        if(i==1){
            fmt.Println(i)
        }else if(i==10){
            fmt.Println("执行")
            goto  breakHader
        }else{
            if(i==5){
                fmt.Println(i)
                break;
            }
        }
    }

breakHader:
    fmt.Print("Message")
}

5.Go函数

//声明函数
func  function_name(param list)(return paramList)
{
  //函数体
}
//demo
func GetMaxNum(a  ,b int)(int){
    //声明一个返回变量
    var result int
    if(aa){
        result=a
    }
    return result
}
//main函数
//noinspection ALL
func  main()  {
    //var i="string";
    var num=GetMaxNum(1,10);
    fmt.Print(num)
}
//匿名函数 把一个函数作为方法的返回值
func function_name func()匿名函数返回值//int {

}

func getSequenes() func()int{
    var i =0
    return func() int{
        i++
        return i;
    }
}
//noinspection ALL
func  main()  {
    sequene := getSequenes()
    fmt.Println(sequene())
    fmt.Println(sequene())
    //var i="string";
    //var num=GetMaxNum(1,10);
    //fmt.Print(num)
}

6.数组声明

[length]Type
[N]Type{value1, value2, ..., valueN}
[...]Type{value1, value2, ..., valueN}  初始化数组
  var 数组名称[] type
  //不指定数组长度
  var 数组名称=[...]int{1,2,3,4,501}
  1. 语言指针

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。指针接受的是一个变量的内存地址 如果直接赋值会报错
访问指针中的值 采用 *指针名称
一个指针变量指向了一个值的内存地址。

//输出变量地址
var n [10]int /* n 是一个长度为 10 的数组 */
n[0]=100
fmt.Printf("变量的地址: %x\n", &n[0]  )
var a=10
//声明指针变量
var  i *int
//存储 &a的地址
i=&a
fmt.Printf("a 变量的地址是: %x\n", &a  )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", i )

/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *i )

8.结构体定义

Go语言中的基础数据类型可以表示一些事务的基本熟悉,但是当我们想表达一个事务的全部或部分属性时,这时候使用单一基本数据类型就无法满足了。Go语言提供了一种自定义数据类型,struct这种类型称之为结构体。我们可以采用struct来定义自己的类型

//语法
type 类型名 struct{
  filedName type
  filedName type
  //1.类型名  标识自定义结构体的名称,在同一个包内不能重复
  //2.字段名 表示结构体字段名。结构体中的字段名必须唯一
  //3.字段类型 表示结构体字段的具体类型 
}
//比如 创建一个Person自定义类型,该类型拥有name和age2个字段
type Person struct{
  name string 
  age int 
}
//结构体实例化 结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型
var 结构体实例 结构体类型
//1.基本实例化
var person Person 
person.name="zhangsan"
person.age=18
//2.匿名结构体
var user struct{name string;age int}
user.name="李四"
user.age=20

//3. 创建指针类型结构体
//采用new关键字对结构体进行实例化,得到的是结构体的地址
var p2=new(Person)
fmt.Println(p2)//&{ 0} 可以看出p2是一个结构指针

//4.取结构体的地址实例化 使用&对结构体进行取地址操作,相当于对该结构体类型进行了一次new实例化操作
var p2=&Person{}
p2.name="张三"
//p2.name="张三"其实在底层是(*p3).name="张三" 这是Go帮我们实现的语法糖

//5.使用键值对初始化 使用键值对对结构体进行初始化时,键对应结构体的字段,值对应字段的初始值
var p4=Person{name: "张三",age: 20}
fmt.Println(p4)//{张三 20}
//使用指针初始化
var p5=&Person{name: "张三",age: 21}
fmt.Println(p5)//&{张三 21}

//6使用值的列表进行初始化
var p6= Person{"张三", 12}
//初始化结构体的时候可以简写,也就是初始化的时候不写键位,直接写值
//使用该初始化操作的时候 
//1.必须初始化结构的所有字段
//2.初始值的填充顺序必须与字段在结构体内的声明顺序一致
//3. 该方式不能和键值初始化方式混用


8.1 构造函数
//Go语言的结构体没有构造函数。所以我们可以自己实现。如果结构体比较复杂的话,值拷贝性能会比较大,所以构造函数返回结构的指针类型
func  NewPerson(name string, age int) *Person {
    return &Person{name, age}
}

8.2 方法和接收者

Go语言中的方法是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Reveiver)。接收者的概念类似于其他语言中的this或者self

func(接收者变量 接收者类型)方法名(参数列表)(返回参数){
 1.接收者变量:接收者中的参数变量命名时,官方建议使用接收者类型名的第一个小写字母。
 2.接收者类型: 接收者类型和参数类似,可以是指针类型和非指针类型
 3.方法名、参数列表、返回参数:具体格式与函数定义相同
}
/Person 结构体
type Person struct {
 name string
 age  int8
}

//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
 return &Person{
     name: name,
     age:  age,
 }
}

//Dream Person做梦的方法
func (p Person) Dream() {
 fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}

func main() {
 p1 := NewPerson("测试", 25)
 p1.Dream()
}
//方法与函数的区别是 函数不属于任何类型,方法属于特定的类型
//方法的接收者类型 可以是指针 也可以不是指针 唯一的区别如下
//Dream Person做梦的方法
func (p Person) Dream() {
    p.name = "张三"
}
func (p *Person) Dreams() {
    p.name = "李四"
}
func main() {
    var p1 = new(Person)
    p1.name = "zs"
    p1.Dream()
    fmt.Println(p1)
    p1.Dreams()
    fmt.Println(p1)
 //输出结果 变量接收者是结构体变量的 无法改变接收者的值
// &{zs 0}
 //指针接收者可以修改接收者内部的值
//&{李四 0}
}

什么时候使用指针类型?

  • 需要修改接收者中的值
  • 接收者是拷贝代价比较大的对象
  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者

8.3 结构体的匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就成为匿名字段

type Person struct{
  string 
  int
}
func main{
 p:=Person{"zk",12}
 //匿名字段默认采用类型名作为字段名,结构体要求字段必须唯一,因此一个结构体中同种类型的匿名字段只能有一个

}

8.4 嵌套结构体

一个结构体种可以嵌套包含另一个结构体或结构体指针

type Address struct{
  Province string
  City string
}
type User struct{
Name string
Address Address
}
func  main(){
  user1 := User{
      Name: "张三",
      Address: Address{
          Province: "浙江",
          City:     "杭州",
      },
  }
   fmt.Println(user1)//{张三 20 {浙江 杭州}}
}

8.5 嵌套匿名结构体

type Address struct{
  Province string
  City    string
    createTime string
}
type User struct{
  Name   string
  Gender string
  Address //匿名结构体
    Email 
}
type Email struct{
  Account string
    createTime string
}

func main() {
  user1 := User{
      Name: "张三",
      Gender: "男",
      Address:Address{
          Province: "浙江",
          City: "杭州",
      },
  }
  fmt.Println(user1.City)//直接访问匿名结构体的字段名
  fmt.Println(user1.Province)
    //对于匿名结构体内部可能存在相同的字段名,这个时候 应该为了避免歧义需要指定具体的内嵌结构体的字段
}

8.6 结构体的"继承"

Go语言中使用结构体也就可以实现其他变成语言中面向对象的继承

type Animal struct {
  name string
}

func (a *Animal) move() {
  fmt.Println(a.name + "移动")
}

type Dog struct {
  Feet int
  *Animal
}

func (d *Dog) wang() {
  fmt.Println(d.name + "WWWW")
}
func main() {
  //继承
  dog := Dog{Feet: 12,
      Animal: &Animal{name: "旺财"}}
  dog.move()
  dog.wang()
}

8.7 结构体字体地可见性

结构体中字段大写开头表示可以公开访问,小写表示私有(仅在定义当前结构体的包中可访问)

8.9 结构体与JSON序列化

JSON是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON键值对是用来保存JS对象的一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号分隔,然后紧接着值;多个键值之间使用英文,分隔

type Student struct {
  No   int    //学号
  Name string //学生名称
}

type Class struct {
  ClassName string //班级名称你
  Students  []*Student
}
//如果有嵌套结构体在内 我们打印外层的结构体可以正常输出 可视化值,但是嵌套中的值输出的都是一串地址 所以我们可以进行重写对应的结构体的String方法 自定义输出效果
func (c *Student) String() string {
  return "{Name:" + c.Name + " " + "No:" + strconv.Itoa(c.No) + "}"
}
func main() {
  class := &Class{
      ClassName: "三年级二班",
      Students:  make([]*Student, 0, 20)}
  for i := 0; i < 100; i++ {
      stu := &Student{
          Name: fmt.Sprintf("stu%02d", i),
          No:   i,
      }
      //追加
      class.Students = append(class.Students, stu)
  }
  //序列化json
  data, _ := json.Marshal(class)
  fmt.Println(data)
  fmt.Printf("json:%s\n", data)
  //json.Marshal默认返回的是一个byte结构
  //[123 34 67 108 97 115 115 78 97 109 101 34 58 34 228 184 137 229 185 180....]
  //json:{"ClassName":"三年级二班","Students":[{"No":0,"Name":"stu00"},{"No":1,"Name":"stu01"},{"No":2,"Name":"stu02"},{"No":3,"Name":"stu03"},{"No":4,"Name":"stu04"},{"No":5,"Name":"stu05"}]}
  //json字符串转换称json
  str := "{\"ClassName\":\"三年级二班\",\"Students\":[{\"No\":0,\"Name\":\"stu00\"},{\"No\":1,\"Name\":\"stu01\"},{\"No\":2,\"Name\":\"stu02\"},{\"No\":3,\"Name\":\"stu03\"},{\"No\":4,\"Name\":\"stu04\"},{\"No\":5,\"Name\":\"stu05\"},{\"No\":6,\"Name\":\"stu06\"}]}"
  //初始化Class
  c := &Class{}
  err := json.Unmarshal([]byte(str), c)
  if err == nil {
      fmt.Println(c)
  }
}

8.10 结构体标签(Tag)

Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来

Tag在机构提字段的后方定义,由一对反引号包裹起来,具体的格式如下:

`key:"value1" key2:"value2"`

结构体标签由一个或多个键值对组成。键与值使用冒号分割,值用双引号括起来。键值对之间使用一个空格分隔。

type Student struct {
  Name string `json:"name"`
  Id   int  //json序列化默认使用字段名作为key
  sex string //私有不能被json包访问
}

func main() {
  stu := &Student{Name: "张三", Id: 1, sex: "男"}
  json, _ := json.Marshal(stu)
  fmt.Println(string(json))//{"name":"张三","Id":1}
}

8.11 map有序输出

func main() {
  //创建一个int键值map数组
  maps := make(map[int]string, 10)
  maps[1] = "A"
  maps[2] = "B"
  maps[3] = "C"
  maps[4] = "D"
  //创建一个存放maps的key值的数组
  var sli []int
  //循环把所有的key放进map当中
  for i, _ := range maps {
      sli = append(sli, i)
  }
  //排序
  sort.Ints(sli)
  //循环输出
  for i := 0; i < len(maps); i++ {
      fmt.Println(maps[sli[i]])
  }
}

9.切片

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片是一种引用类型

新获得的切片跟源切片底层对应的数组都是同一个,所以对其中一个切片元素的修改也会影响到另外一个

声明切片语法 
make([]type, length, capacity)
make([]type, length)
[]type{}
[]type{value1, value2,..., valueN}

s[n]             切片s中索引位置为n的项
s[n:m]           从切片s的索引位置n到m-1处所获得的切片
s[n:]            从切片s的索引位置到len(s)-1处所获得的切片
s[:m]            从切片s的索引位置0到m-1处所获得的切片
s[:]             从切片s的索引位置0到len(s)-1处获得的切片
var identifier []type
切片初始化
s:=[]int{1,2,3}

/* 创建切片  长度为4 最长长度可以达到4*/
    slice := make([]int, 2, 4)
    append_slice := []int{1, 2}
    fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n",      slice, len(slice), cap(slice), slice)
//追加2个元素 地址未改变
    slice = append(slice, append_slice...)
    fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
//继续追加 地址改变
    slice = append(slice, 10, 20)
    fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)

    slice = append(slice, 30, 40, 50)
    fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
    
    
slice addr:0xc000052140 len:2 cap:4 slice:[0 0]
slice addr:0xc000052140 len:4 cap:4 slice:[0 0 1 2]
slice addr:0xc00006c140 len:6 cap:8 slice:[0 0 1 2 10 20]
slice addr:0xc00008a000 len:9 cap:16 slice:[0 0 1 2 10 20 30 40 50]

10.创建Map集合

//声明map的方式
var hashMap=make(map[keyType]valueType);
var hashMap=make(map[string]string)

    hashMap["Lucy"]="张三"
    hashMap["Ad"]="Nike"

    for k, v := range hashMap {
        fmt.Println(k+"\t"+v)
    }
    //删除函数
    delete(hashMap,"Lucy")
    for k, v := range hashMap {
        fmt.Println(k+"\t"+v)
    }

11.类型转换

type_name(exp)

var name=12 
var str=string(12)
//string转int
nb,_=strconv.Atio(str)
//string转 int 64
in64, err := strconv.ParseInt(string, 10, 64)
//int转换成string
string := strconv.Itoa(int)
//int64转换成 string
string := strconv.FormatInt(int64,10)

12.接口定义 实现

demo

//定义一个say的接口
type Say interface {
    sayHelloWorld();
}
type  sayHello struct {

}
type saySpeak struct {

}

//实现类
func (say sayHello) sayHelloWorld()  {
      fmt.Println("helloworld")
}

//实现类
func ( saySpeak saySpeak)sayHelloWorld(){
    fmt.Println("Nice")
}

func main() {
    var say Say
    say=new(sayHello)
    say.sayHelloWorld();

    say=new(saySpeak);
    say.sayHelloWorld();

}

13 异常情况

package main

import (
    "fmt"
)

// 定义一个 DivideError 结构
type DivideError struct {
    dividee int
    divider int
}

// 实现 `error` 接口
func (de *DivideError) Error() string {
    strFormat := `
    Cannot proceed, the divider is zero.
    dividee: %d
    divider: 0
`
    return fmt.Sprintf(strFormat, de.dividee)
}

// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
    if varDivider == 0 {
            dData := DivideError{
                    dividee: varDividee,
                    divider: varDivider,
            }
            errorMsg = dData.Error()
            return
    } else {
            return varDividee / varDivider, ""
    }

}

func main() {

    // 正常情况
    if result, errorMsg := Divide(100, 10); errorMsg == "" {
            fmt.Println("100/10 = ", result)
    }
    // 当被除数为零的时候会返回错误信息
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
            fmt.Println("errorMsg is: ", errorMsg)
    }

}

你可能感兴趣的:(Golang基础语法)