GO超详细基础语法&黑点

本文深入探讨了Go语言的独特特性,包括其对进程、线程和协程的处理方式,内存管理,以及对对象创建、defer语句、泛型支持、数据类型处理等方面的详细解析。此外,还介绍了Go语言在数组、切片、map等数据结构上的特点,以及其面向接口的编程理念。

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

更新:
进程有自己独立的堆和栈,不共享堆和栈。
线程有自己独立的栈和共享的堆,不共享栈。
协程和线程一样共享堆,不共享栈。协程有程序员在协程的代码里显示调度。

执行协程只需要极少的栈内存(大概是4~5KB),默认情况下,线程栈的大小为1MB。

最新更新

GO的黑点

GC1.0在32位环境下有重大缺陷,导致整个进程停顿严重。只能减少进程中的对象,将它的间歇性停顿控制在可接受范围内。

禁止未使用变量和多余import,存在则编译错误,如import某数据库驱动的pkg,删掉编译通过但是运行时必然报错,找不到数据库驱动。

创建对象的方式太多令人纠结

defer的语义定义设定不够合理
有无限循环语句不停地创建资源,defer语句得不到执行
系统存储defer列表也要格外占用资源

defer设定在所属代码块结束时执行,更好

没有泛型支持
list,set这些常见的数据类型的接口,放进去的对象是一个具体的类型,取出来只能是无类型的interface{},得强制类型之后才能继续使用

实现接口不需要明确声明
http://blog.zhaojie.me/2013/04/why-i-dont-like-go-style-interface-or-structural-typing.html

静态编译的文件尺寸很大


complex浮点数
rune(32位)4个字节 ,相当于C 语言的Char
变量类型写在变量名之后
函数返回类型也写在方法最后,如fun grade( score int) string{}
var a=可以写作a:=
编译器自动推测变量类型
原生支持复数
枚举const(b=iota)(自增)

if条件不需要括号
if可以赋值
if可以把判断语句写在;后面

for也不带括号
初始,结束条件,递增表达都可以省略

switch自动带break,后面可以不跟条件判断
用传入分数来判断成绩等级
switch score{}的话必须内部是score=XX,来我们内部是grade="A"等等,所以要直接switch

返回两个值的函数,只想return第一个值:
q,_:=div(a,b)
return q


函数也可以作为其他函数的参数
没有默认参数,可选参数,没有重载
反射:runtime.FuncForPC().Name()
数组:数组名…
i:=range 数组名

GO语言只支持值传递(经典的i++不改变输出值)


数组、切片、容器
arr:=[3]int{1,3,5}这种写法必须要初始化
for i,v:=range arr3{
fmt.Println(i,v)//同时获得序号和值
}

[10]int和[20]int是不同类型
调用func f(arr [10] int)打印拷贝后加工过的数组
直接打印原来arr还是原来的那些值
没有C语言的:数组名就是数组头指针

切片
arr[:]打印全部
arr[2:6]打印下标2到5
slice改变的东西会一直保持修改后的状态
slice本身没有数据,是对底层array的一个view
reslice:slice的slice 即使下标不被包含在二次slice后的内容里,也能打印出来

slice可以向后扩展
原因:在这里插入图片描述

向slice添加元素 如果超越cap,系统会分配更大的底层数组
分配cap由1 2 4一直到128

s :=make([]int,16)
s :=make([]int,16,32)

copy(s2,s1)让s1替换s2的相应部分
假如要删除[0 2 4 6 8 0 0 0 0]中的8,用s=append(s[:4],s[4:])
删除第一个
front:=s[0]
s=s[1:]
删除队尾
tail:=s[len(s)-1]
s=s[:len(s)-1]
slice扩容可以参考:
https://www.cnblogs.com/junneyang/p/6074786.html


map定义:map[K]V
复合map:map[K1]map[K2]V
打印顺序不是定义顺序,是无序的
m:=make(map[string] int)自动初始化为空
for k,v range m{
fmt.Print(k,v)}

取值
name,ok:=m[K]
fmt.Println(name,ok)//打印名字和true or false

delete(m,“name”)
Java要实现HashCode和Equals才能作为key

map使用哈希表,必须可以比较相等
除了slice,map,fuction的内建类型都可以作为key


最长不重复字串
核心函数

for i,ch:=range []byte(s){
   lastI,ok:=lastOccured[ch]//lastI是遍历的字符的上一次出现过的下标,默认为0因为map的V默认没有内容,Ok代表V是否有内容,也就是是否出现过

   if ok&&lastI>=start {
      start=lastI+1//关键要理解这里的start即最长不重复字串的开头必须要在上一个出现了的字母的后面
   }
   if i-start+1>maxlength{
      maxlength=i-start+1
   }
   lastOccured[ch]=i
   fmt.Println(ch,lastI,start,ok,maxlength,lastOccured[ch])
}
return maxlength

%X打印字节数,使用utf8.RuneCOuntInString()获得字符数,len获得字节数,[]byte获得字节

其他操作在strings包里面 fileds join split contains index 等


面向对象:
只支持封装,不支持继承和多态
只有struct,没有class

不论地址还是结构本身, 都用.来访问成员
局部变量放在堆上还是栈上不需要知道,GC会决定

为结构定义方法:
接受的参数写在方法前面的()
func(node *TreeNode)setValue(value int){
node.value=value;
}

接收者,即是任意类型(结构体,指针,接口等)的实例。函数跟类型绑定,即成了方法

只有指针才可以改变结构内容
nil指针也可以调用方法

遍历树:
func(node *treeNode) traverse(){
if node==nil{
return
}

node.left.traverse()
node.print()
node.right.traverse()
}


首字母大写代表public
首字母小写代表private
每个目录只能有一个包
包名可以跟目录名不一样

扩充系统类型或用别人的类型:
定义别名
使用组合


面向接口的编程语言,不是面向对象
duck typing。像鸭子走路,像鸭子叫,就是鸭子
描述事物的外部行为而非内部结构

python
def download(retriever):
return retriever.get("")
//运行时才知道retriever有没有get
C++
template
string download(const R& retriever){
return retriever.get("")}
//编译时才知道传入的retriever有没有get
java一定要继承接口 但有时需要两个接口的功能,java做不到

同时有python的灵活性,又有java的类型检查


接口由使用者定义
接口必须要有结构体

/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
   /* variables */
}

/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法实现 */
}

接口 接口=new (结构体)


defer 在return前把函数执行
defer先进后出
使用的时机:Open/Close,Lock/Unlock,PrintHeader/PrintFooter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值