go语言学习

一、基础语法

1.变量定义

package main

import "fmt"

func main(){
	//定义变量:var
	//常量定义:const

	//01-先定义变量,再赋值, var 变量名 数据类型
	var name string
	name = "chenran"

	var age int
	age = 20

	fmt.Println("name",name)
	fmt.Printf("name is: %s, age is:%d\n", name,age)

	//02-定义时直接赋值
	var gender = "man"
	fmt.Println("gender:" ,gender)

	//03-定义直接赋值,使用自动推导,(最常用)
	address := "成都"
	fmt.Println("address:", address)

	//04-平行赋值
	i, j := 10,20
	fmt.Println("i:", i , "j:",j)
	i, j = j, i
	fmt.Println("i:", i , "j:",j) 

}

2.基础数据类型

int, int8,int16, int32, int64

uint ...uint64

float32, float64

true/false

3.自增语法

i++, i-- ,自增语法必须单独一行

package main

import "fmt"

func main(){
	i := 20
	i++
	fmt.Println("i:",i)
}

4.指针

package main

import "fmt"

func main(){
	//使用指针时会使用垃圾回收机制(gc:garbage collector),开发人员不需要手动释放内存
	//可以返回栈上的指针,编译时就确定了变量的分配位置
	//编译的时候,如果发现有必要的话,就将变量分配到堆上

	name := "lily"
	ptr := &name
	fmt.Println("name:", name)
	fmt.Println("name ptr:", ptr)

	//02-使用new关键字定义,提前定义一个指针,对指针赋值
	name2ptr := new(string)
	*name2ptr = "duck"
	fmt.Println("name2:", *name2ptr)
	fmt.Println("name2 ptr:", name2ptr)

	//可以返回栈上的指针,编译器编译程序时,会自动判断这段代码,将city变量分配到堆上
	res := testptr()
	fmt.Println("res city:", *res, "address:", res)

    //空指针:nil
	//if两端不用加(),加{}
	if res == nil{
		fmt.Println("res是空,nil")
	}else{
		fmt.Println("res是非空")
	}
}

//定义一个函数,返回一个string类型指针,go语言返回写在参数列表后面
func testptr() *string {
	city := "上海"
	ptr := &city
	return ptr

}

5.string

package main

import "fmt"

func main(){
	//01-定义
	name := "duck"

	//需要换行,原生输出字符串时,使用反引号``
	usage := `./a.out <option>
		-h help
		-a xxxx`

	fmt.Println("name:",name)
	fmt.Println("usage:",usage)

	//02-长度,访问
	//string没有length方法,可以使用自由函数len()
	ll := len(name)
	fmt.Println("ll:",ll)

	//不需要加()
	for i :=0; i < len(name); i++{
		fmt.Printf("i: %d, v: %c\n",i, name[i])
	}

	//03-拼接
	i, j := "hello","world"
	fmt.Println("i+j=", i+j)

	//使用const修饰为常量,不能修改
	const address = "beijing"
	//address = ’上海‘
	fmt.Println("address:", address)

}

*6 数组和切片(Go 语言切片面试真题 8 连问

1、数组和切片的区别

  • a.数组是固定长度,不能动态扩容,在编译期就确定大小。
  • b.切片是对数组的抽象(动态数组),切片长度不固定,可以追加元素。切片不是数组,切片描述的是一块数组。切片可以使用append追加元素,当cap不足时动态扩容。

2、拷贝大切片代价比拷贝小切片代价大吗?
不会。
切片本质内部结构如下:如果发生拷贝,本质上就是拷贝下面的三个字断。

type SliceHeader struct {
 Data uintptr
 Len  int
 Cap  int
}


3、深拷贝和浅拷贝
本质区别:复制出来的对象与原对象是否会指向同一地址

切片拷贝三种方式:

  • a.使用“=”拷贝,浅拷贝
  • b.使用“[:]”下标的方式复制切片,浅拷贝
  • c.使用内置函数copy()进行切片拷贝,深拷贝

4、零切片、空切片、nil切片是什么

  • 零切片:切片内部数组都是零值或者底层数组的内容全是nil的切片;使用make创建的、长度、容量都不为零的切片就是零切片。
  • nil切片:nil切片的长度和容量都为0,且和nil比较的结果都为true;采用直接创建切片的方式、new创建切片的方式都可以创建nil切片。
  • 空切片:空切片的长度和容量都是0,但是和nil的比较结果是false,因为所有空切片的数据指针都是指向同一个地址;使用字面量、make可以创建空切片。


5、切片的扩容策略
切片在扩容时会进行内容对齐,这个和内存分配策略有关。当原slice容量小于1024时,新slice容量变为原来的2倍;当原slice容量超过1024时,新slice容量变成原来的1.25倍。

6、参数传递切片和切片指针有什么区别?
当切片作为参数传递时,其实就是一个结构体的传递,因为Go语言参数传递只有值传递,传递一个切片就会浅拷贝原切片,但因为底层数据的地址没有改变,所以在函数内对切片的修改,也会影响到函数外的切片。​​​​​​​
例外:如果指向底层数组的指针被覆盖或者修改(copy、重分配、append触发扩容),此时函数内部对数据的修改将不再影响到外部的切片,代表长度的len和容量cap也均不会被修改。因为函数外的切片已经指向了一个新的底层数组。

func modifySlice(s []string)  {
 s[0] = "song"
 s[1] = "Golang"
 fmt.Println("out slice: ", s)
}

func main()  {
 s := []string{"asong", "Golang梦工厂"}
 modifySlice(s)
 fmt.Println("inner slice: ", s)
}
// 运行结果
out slice:  [song Golang]
inner slice:  [song Golang]


//特例
func appendSlice(s []string)  {
 s = append(s, "快关注!!")
 fmt.Println("out slice: ", s)
}

func main()  {
 s := []string{"asong", "Golang梦工厂"}
 appendSlice(s)
 fmt.Println("inner slice: ", s)
}
// 运行结果
out slice:  [asong Golang梦工厂 快关注!!]
inner slice:  [asong Golang梦工厂]

7、range遍历切片有什么要注意
range关键字用于for循环中迭代数组(array)、切片(slice)、通道(channel)、集合(map)的元素。两种使用方式:
使用range遍历切片时会先拷贝一份,然后再遍历拷贝数据。
​​​​​​​面试官:go中for-range使用过吗?这几个问题你能解释一下原因吗?

for k,v := range _ { } //遍历下标和对应值。
for k := range _ { } //只遍历下标

6.定长数组

package main

import "fmt"

func main(){

	//1-定义一个具有10个数字的数组
	//nums := [10]int{1,2,3,4}
	//var nums = [10]int{1,2,3,4}

	nums := [10]int{1,2,3,4,5}

	//2-遍历
	for i :=0; i<len(nums); i++{
		fmt.Println("i:", i, "j:", nums[i])
	}

	//方式二:for range ===>python支持
	//value全程是一个临时变量,不断重新赋值,修改它不会修改原始数组
	for key,value := range nums{
		fmt.Println("key:",key, "value:",value)
	}
	
	//想忽略一个值,可以使用_
	//如果想忽略两个,不能使用:=,使用=, 有:表示两边有新东西
	for _, value := range nums{
		fmt.Println("忽略key,value:",value)
	}
	
	//不定长数组
	//3-使用make创建数组
}

7.不定长数组(切片,slice)

切片1

package main

import "fmt"

func main(){
	//切片:slice,它的底层是数组,可以动态改变长度
	//定义一个切片,包含多个地名
	//names := []string{"北京","上海","广州","深圳"}
	names := []string{"北京","上海","广州","深圳"}

	for i ,v := range names{
		fmt.Println("i:",i, "v:",v)
	}

	//1.追加数据
	fmt.Println("追加元素之前,names的长度:",len(names),",容量:",cap(names))
	names = append(names,"海南")
	fmt.Println("names追加元素后赋值给自己:",names)
	fmt.Println("追加元素之后,names的长度:",len(names),",容量:",cap(names)
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值