Go学习日记 :基础 第一章 语法

本文介绍了Go语言的基础语法,包括变量定义、内建变量类型、指针、面向对象特性等。Go语言的变量可以自动类型推断,不支持隐式类型转换,main函数不接受参数。此外,Go中的数组是值类型,切片是对数组的视图,Map是哈希表,不支持继承和多态,但支持面向接口编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于Go的知识:

默认情况下都会使用静态链接,编译完的go程序都是二进制文件,有非常好的便捷性,可以拷贝到不同的机器上运行

并且go与其他主流语言相比,它的关键字比较少只有25个关键字,c有37个,c++的84个

与其他语言的差异:

  Go中main函数不支持任何返回值

  通过os.Exit来返回状态

func main() {  //func main () int{
	fmt.Println("hello word")
	os.Exit(-1) //return 1 -1 状态值
 }

  main函数不支持传入参数

func main (arg []string)

  在程序中直接通过os.Args获取命令行参数

if len(os.Args)>1{
		fmt.Println("Hello word",os.Args[1])
	}
	os.Exit(-1)

 

1.变量定义

 var a int = 1 // var a,b,c =1,"2",4
 编译器可以自动识别类型

 a,b := 1,2(只能初次定义使用,包外部不可用)
 
 var (
  a = '1'
 )

与其他主要编程语言的差异:

   赋值可以进行自动类型推断

   在一个赋值语句可以对多个变量进行同时赋值 

	a,b=b,a //可以这样使用交换值

2.内建变量类型


  bool、string
  无符号:(u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr 指针
  byte(8位),rune (字符型)32位
  float32,float64,complex64(复数,实部和虚部分别是32位)、complex128(复数,实部和虚部64位)
  复数:

欧拉公式:

与其他主要编程语言的差异:

 1、GO语言不允许隐士类型转换(主流语言一般潜在的规则就是小的类型可以往大的类型进行转换)

 2、别名和原有类型也不能进行隐士类型转换

type MyInt int64

func Test(t *testing.T){
  var a int 32=1
  var b int64
  b=int64(a)
  var c MyInt
  c= b//错误,不支持别名的因式转换
}

 类型的预定义值:

   math.MaxInt64

   math.MaxFloat64

  math.MaxUint32

 

指针类型:

  go语言和java一样支持了垃圾回收的机制,但是作为非常高效的语言,也支持使用指针访问内存空间,但是是有一些限制的

与其他编程语言的差异:

  1、不支持指针运算

    a:=1
	aptr:=&a
    aptr=aptr+1 //因为平常可以使用指针的自增来访问连续的存储空间例如数组
	t.Log(a,aptr)
	t.Logf("%T %T",a,aptr)
  

 编译结果:

  2、string是值类型,其默认的初始化为空字符串,而不是nil

if s==" "{  //不能判断 s== nil

}

3、常量 

const a,b = 3,5
var c = int 
fmt.Print(int(math.Sqrt(a*b+c+d)))

4、枚举类型:
 
 go语言没有特殊的枚举关键字,所以用一组const来定义表示
 普通枚举:

 const(
  cpp =0
  java = 1
  py = 2
 )


 自增枚举:

const (
	Modoy=iota +1
	Tuesday
	Wednesday
)


 5、复杂运算:

 go语言没有前置的++,--

用==比较数组:在主流的语言中数组是个引用类型不是值类型,用等号比较其实是比较两个数组的引用,不是比较值是否相同,这点在go中完全相反的,如果维数相等且含有相同个数元素的数组是可以比较的,每个元素都相同的才相等


  //b,kb,mb,gb,tb,pb
    const(
        b = 1<<(10*iota)
        kb
        mb
        gb
    )
可以作为一个自增值的种子

6、位运算符: 

  与其他主要编程语言的差异

 

7、判断语句 if
 

 if content,err := ioutil.ReadFile(filename);err=null{
  fmt.PrintIn(string(content))
 }else{
  fmt=PrintIn("content is err",err)
 }

与其他语言的差异:

1、condition表达式结构必须为布尔值

2、支持变量赋值

if var declartion; condition{
// if a:=1==1; a{


}
//平常用到: 因为go语言函数支持多返回值,所以这样写
 if v,err:=someFun(); err==nill{
   t.Log()
 }else{
  t.Log()
  }

 

8、switch条件

 func grade(score int)string{
    g := ""
    switch{
     case score<0||score>100:
    panic(fmt.Sprint("Wrong scroe : %d", score))
    case score < 60:
        g = "F"
    case score< 80:
        g ="C"
    }
    return g
 }


 go语言的switch自带berak

与其他语言的差异:

实例:

func TestSwitch(t *testing.T){
	for i:=0;i<5;i++{
		switch i {
		case 0,2:
			t.Log("Even")
		case 1,3:
			t.Log("Odd")
		default:
			t.Log("it is not 0-3")
		}
	}
}

9、循环:for

 for ; ; {}
 func printFile(){
   filname := "123.txt"
   file,err := os.Open(filename)
   if err!=nill{
   panic(err)
   }
   scanner=bufio.NewScanner(file)
   for scanner.Scan(){
    fmt.PrintIn(scanner.Text())
   }

 }
//条件循环
n:=0
for n<5{
}

//无限循环
//while(true)
 n:=0
 for{}


 

 10、指针
   var a int =2
   var pa *int =&a
   *pa =3
   指针不能运算
   Go语言只有值传递一种方式
   当 func f(pa *int)的时候,相当于把地址进行传递
   当 func f(cache Cache)的时候,相当于直接把cache里面pDate指针拷贝过去,都是指向data
   func swap(a,b *int){
   *b,*a=*a,*b
   }
   swap(&a,&b)

11、数组:

 var arr1 [3][4]int
 arr2 :=[4]int {3,4,5,6}
 arr3 :=[...]int{123,23,4,5}
 var arrs [3][4] int

数组遍历:

   for i:=0;i<len(arr3);i++{
		t.Log(arr3[i])
	}
	for idx,e:=range arr3{  //idx 索引值 或者 _,e 或者 e
		t.Log(idx,e)
	}


  i是数组下标,v为值 类似于foreach
 数组是值类型
   [10]int 和[20]int 是不同类型
   调用func f(arr [10]int)会拷贝数组
   在go语言不直接使用数组,而使用切片

数组截取:也就是切片


12、切片
   slice本身是没有数据的,是对底层array的一个视图,相对容易造成大量GC,是一个连续数据存储结构,表明上是一个可变长的数组,其实内部是一个结构体

 其中ptr指针指向一个连续的存储空间

这个时候报错,其中len代表可以访问的元素,cap内部容量,其中len个元素被初始化为默认零值,未初始化元素不可以访问

实例一:切片如何实现可变长

 cpa呈2倍增长,在append时候为什么要赋值,是因为这里的连续存储空间的地址发生了变化,并不是总是在原有的内存空间上添加这个值,当初存储空间需要扩展的时候,会创建一个新的存储空间并且把原有的数组拷贝过来
实例二:
   

 arr := [...]int{0,2,3,4,5,6}
    fmt.Println(arr[2:6],arr[:6],arr[2:],arr[:])

  还可以resilic
   

  s:=arr[2:6]
     s = s[:3]
     s=s[1:]
     s=arr[:]  //和指针相同

 slice的扩展:
    问题一:

  arr:=[]int{0,1,2,3,4,5,6}
     s1:=arr[2,6]
     s2:=s1[3:5]

     s1=[2,3,4,5]  s2=[5,6]   

其中len会改变,但是cap从截取的位置开始到末尾,所以s1指向后端连续存储空间,以下实例验证

当我们修改summer的时候,Q2也发生改变

cap=cap(s1)


 添加元素如果超过cap,系统会重新分配更大的底层数组
 由于值传递的关系,必须接受append的返回值
 s=append(s,val)

 var s []int //zero value for slice is nil
 s = append(s,2*i+1)//当cap每次装不下的时候会*2
 还可以这样创建:
  s2 :=make([]int,16) //len=6
  s3 :=make([]int,10,32) //len=10,cap=32
  copy: copy (s2,s1) //把s1拷贝到s2
  del:中间的下标3的元素: s2=append(s2[:3],s2[4:]...)
  从头和从尾去掉:
  front :=s2[0]
  s2=s2[1:]

  tail := s2[len(s2)-1]
  s2=s2[:len(s2)-1]

    如果创建一个长度为16的slice:
      s2 := make([]int,16)
    创建一个有10个元素,但是数组有32个长度
      s3 :=make([]int,10,32)
    删除下标为3的元素
     s2=append(s2[:3],s2[4:]...)
     len会改变,cap不会改变
    删除首尾:
     s2=s2[1:]
     s2=sw[:len(s2)-1 ]

数组和切片:

1、容量可以伸缩

2、是否可以比较,数组只要维数相同,长度相同可以进行比较,只要里面元素都相同,那么数组相同,切片不可以比较


 13、Map: 
   map[K]V,map[K1]map[K2]V


  声明实例:
  创建:

map := map[string]string{
    "name":"123",
  }  
  var m2 map[string] int    //m2=nil
  m3 :=make(map[string]int)    //m3=empty map


  遍历:k在map中是无序的,是hash map,需要给key进行排序,把key取出来放到slice中,排序完再去遍历map

   for k,v/_,v/k :=range m{

   }
func TestTMap(t *testing.T) {
	m1:=map[int]int{1:1,2:4,3:9}
	for k,v :=range m1{
		t.Log(k,v)
	}
}

取值:

 if name,ok:=m["name"];ok{
    fmt.Println(name,ok)
   }else{
   fmt.Println(name,ok)
   }

删除:    
 

  delete(m,"name")
  map的key:

  1>map使用哈希表,必须可以比较相等
  2>除了slice,map,function的内建类型都可以作为key
  3>Struct类型不包括上述字段也可以作为key

与其他编程语言的差异:

在访问的key不存在的时候,仍然返回零值,不能通过返回nill来判断元素是否存在

其中主要的判断方式:

面向对象


   go语言仅支持封装,不支持继承和多态,没有class只有struct
   创建结构体:
     type treeNode struct{
     value int
     left,right *treeNode
     }
     func (node treeNode) print(){ //treeNode结构体内的方法,go语言都是传值的
   fmt.Println(node.value)
}
    实例化:
      root :=treeNode{}
      root.left=&treeNode{}
      root.right.left=new(treeNode)
      nodes:=[]treeNode{
        {value:2}
        {}
        {1,nil,nil},
      }
    工厂函数:
      funct createNode(value int )*treeNode{
       return &treeNode{value:value} //返回局部变量的地址
      }

接口:
  go语言是面向接口的编程语言,没有继承和多态,通过接口完成
  duck typing:描述事务的外部行为而非内部结构
  严格说go属于结构化类型系统,类似duck typing
  go语言的接口是由使用者定义
  接口类:

type Retriever interface {
	Get(url string) string  //在interface中不用加func
}
func download(r Retriever) string{  //使用者
	return  r.Get("http://www.imooc.com")
}

func main() {
	var r Retriever
	r=mock.Retrievers{"this is a fake imooc.com"}
	//r=mock.Retrievers{"this is a fake imooc.com"}
	r=real.Retriever{}
	fmt.Println(download(r))
	//fmt.Println(download(r))
}

实现类:

type Retriever struct {
	UserAgent string
	TimeOut time.Duration
}

func(r Retriever) Get(url string) string{
	resp,err:=http.Get(url)
	if err!=nil{
		panic(err)
	}
	result,err:=httputil.DumpResponse(resp,true)
	resp.Body.Close()
	if err!=nil{
		panic(err)
	}
	return  string(result)
}

在r的里面有两个内容,一个类型,一个值

func inspect(r Retriever){
	fmt.Printf("%T %v\n",r,r)
//第二种打印方式
	switch v:=r.(type) {
	case mock.Retrievers:
         fmt.Println("content:",v.Contentst)
	case *real.Retriever:
		fmt.Println("UserAgent:",v.UserAgent)

	}
}
func main() {
	var r Retriever
	inspect(r)
	r=mock.Retrievers{"this is a fake imooc.com"}
	//r=mock.Retrievers{"this is a fake imooc.com"}
	inspect(r)
	r=&real.Retriever{UserAgent:"Mozilla/5.0",TimeOut:time.Minute}
   //fmt.Printf("%T %v\n",r,r) 第一种打印方式
	inspect(r)
	//fmt.Println(download(r))
	//fmt.Println(download(r))
//第三种打印方式
      realRetriever := r.(*real.Retriever)
      fmt.Println(realRetriever.TimeOut)
	if mockRetriever,ok:=r.(mock.Retrievers);ok{
		fmt.Println(mockRetriever.Contentst)
	}else{
		fmt.Println("not a mock retriever")
	}
}

   接口变量里面有:实现者的类型、实现者的值(或者是实现者的指针指向实现者)
   接口变量自带指针,接口变量统一采用值传递,几乎不需要使用接口的指针
   指针接受者实现只能以指针方式使用,值接收者都可以 
   func的返回类型如果是interface的话不限制返回类型,但是可以在返回值时添加类型限制,比如 return head.(int )

   常用的接口:

   string:
        func (r *Retrievers)String()string{
        return  fmt.Sprintf(
            "Retriever:{Contents=%s}",r.Contentst)
}
 


   Read:实现的人读取文件给你的[]byte里面
   Write:写入到文件里面 

函数式编程:
   函数是一等公民:参数,变量,返回值都可以是函数
   高阶函数:函数的参数也可以是函数
 

   func adder() func(int)int{
    sum:=0
    fmt.Println(sum)
    return func(v int) int {
        sum+=v
        return  sum
    }
}
func main() {
    a:=adder()
    fmt.Println("............")
    for i:=0;i<10;i++{
        fmt.Println(a(i))
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值