Go语言学习--避坑版

   本博文主要整理一些Go语言的特点,适宜于有go语法基础的同学,帮助大家一起扫盲golang,如需转载请联系作者

1.++,--

golang语法中,只有a++;a--;    不存在--a;++a语法

2.String

1. Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样。
而Java中String不属于基本数据类型

2. 通过下标直接获取字符串中某个元素的值
例如:s:="abc"  //s[0]=a

3.boolean

Go 语言中不允许将整型强制转换为布尔型.

布尔型无法参与数值运算,也无法与其他类型进行转换。
例如java执行下面的语句可以编译通过
if(1){System.out.println("条件为真")}
但是Golang执行对应的语句报错,错误信息为//non-bool 0 (type int) used as if condition
if(1){fmt.Println("条件为真")}

 4.defer

defer 延迟调用
如果存在多个defer是,按照先进后出的顺序执行

5.数组比较

golang提供了数组比较的原生方法

num1 := [5]int{2, 2, 3, 4, 5}
num2 := [5]int{1, 2, 3, 4, 5}
num1 == num2 //相等为true,不相等为false
num1 != num2

6.切片

大家在学其他强类型编程语言时,多么渴望数组能够动态变化。Go语言中,就有切片可以解决,让您使用起来随心所欲;
切片,是解决数组的长度无法变化的利器,切片可进行拼接,长度自由等好处;
切片的本质是就是结构体

7.类型转换(特殊)

// 平常我们常见的类型转换格式:(类型)变量 ,int a; (float)a
// golang还有另外一种类型转换方式
userLogin, _ := bc.Get("user") // userLogin的类型:interface{}
u := userLogin.(*services.User) // 将userLogin 强转为User类型

8.结构体打印(类似java的toString()方法)

打印 Go 结构体(struct)信息:fmt.Printf("%+v", user)

代码:
package main
 
import "fmt"
 
// 用户
type User struct {
    Id   int
    Name string
    Age  int
}
 
func main() {
    user := User{Id:2, Name:"golang"}
 
    // 打印 结构体
    fmt.Printf("%+v", user)
 
    // 输出换行符
    fmt.Printf("\n")
 
    // 判断实例是否为空
    fmt.Println(user == User{})
}


输出:
{Id:2 Name:golang Age:0}
false

9.golang提供的MD5加密方法

golang 的md5加密 - Go语言中文网 - Golang中文社区

10.interface{}与struct

interface 针对方法的定义
struct 针对普通的数据结构定义

深入了解:https://www.cnblogs.com/zhangdewang/p/10612089.html

11.切片传参、map传参时原值会被修改,而结构体、普通数组传参时原值不会被改变。

     形参所在函数中,切片参数使用append,凭拼接的数据对原数据不会有影响,下面会有提到。

// 切片、map作为参数传参时,在被传参的函数中修改值,会影响原函数中数据、map的值

// 以map举例

func main() {
	m := map[int]string{1: "鱼儿", 2: "虾米"}
	fmt.Println("传参前:", m)
	update(m)
	fmt.Println("传参后:", m)
}

func update(m map[int]string) {
	m[1] = "鱼儿不存在"
}



**深度分析切片传参原值会被影响的原因**
/*
因为slice本质就是结构体,结构体里面有一个元素array 值指针类型(保存array的空间地址),作为参数传值时,其实就是传指针。如上函数举例:update方法实际就是获取array指针(array实际空间地址)进行操作,所以main函数打印时,发现原数据已经被修改。
*/
type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

12.指针*,与中括号[]的优先级

中括号[] 优先级高于 指针符号*

13.数组指针有P[0]的简写方式,切片指针没有p[0]的写法(区别)

func main() {
	s := []int{1, 2, 3, 54}
	var p *[]int
	p = &s
	fmt.Println(p)
	fmt.Println(*p)
	fmt.Println((*p)[0])
	fmt.Println(p[0]) // 此处报错!数组指针有P[0]的简写方式,切片指针没有p[0]的写法
}

14.浅拷贝、深拷贝的概念

浅拷贝:仅仅考别的变量的值,没有对指向的空间进行任何的拷贝
深拷贝:将原有的变量的空间全部拷贝一份

15 .可以通过append方法对切片进行动态扩容,但是对原数据没有影响。但是通过不同的切片定义方式,使用append方法后,再修改原数据包含下标的数据,对原数据都是没有影响的。原因:当使用append()方法后,就会自动创建新的空间,所以对原数据没有影响

func main() {
	//a := []int{1, 2, 3, 4, 5} //无论哪种切片的定义方式、无论空余cap多大,一旦涉及append,就会重新生成一个新的空间进行拼接
	var a = make([]int, 2, 10) // 使用该方式定义切片,modify()修改的值会改变main()值;使用上面自动推导类型定义,modify()修改的值不会改变
	a = []int{8, 9}
	//fmt.Println("a2:", a2)
	fmt.Println("原函数1", a)
	modify(a)
	fmt.Println("原函数2", a)
}
func modify(a1 []int) {
	// 使用append进行动态扩容时,a的指向不再是主函数a的空间,而是指向新的空间
	a1 = append(a1, 21) //注释该行代码,即可修改主函数中的数据
	a1[0] = 111
	fmt.Println(a1)
}

16.switch  golang语法中的switch与java等其他语言的语法不太相同

    查看https://www.jianshu.com/p/bb3cf84721ab

17.调用结构体的3种方式

// 方法值与方法表达式
type People struct {
	id   int
	name string
}

func (p *People) PrintInfo() {
	fmt.Println(*p)
}

func main() {
	p := People{101, "小明"}
	// 方式一:直接调用方法
	p.PrintInfo()
	// 方式二:方法值
	f := p.PrintInfo //可以打印下f的类型
	fmt.Printf("f的类型:%T\n", f)
	f()
	// 方式三:方法表达式
	f_ := (*People).PrintInfo
	f_(&p)
}

结果:

18.文件操作,写入数据(三种方式)

// 方式一:WriteString
n,err:=file.WriteString("Hello World")

// 方式二:Write
var str string="Hello World"
n,err:=file.Write([]byte(str))

// 方式三:WriteAt
n,err:=file.WriteAt([]byte(str),0)//第二个参数,off表示在指定的位置重置写入数据

// 获取文件的长度,通常与WriteAt的长度结合使用
file.Seek(offset,io.SeekEnd)//将光标定位到文件中原有内容的后面,返回文件中原有数据的长度。其中offset表示在yauncheng文件后面空出的长度

19.go也能开发桌面软件-go get github.com/lxn/walk

20.判断map中的key,value是否存在

/*
	   判断map中的key,value是否存在
	*/
	m11 := map[int]string{}
	m11[1] = "123"
	m11[2] = "223"
	m11[3] = "323"
	m11[100] = "423"
	m11[5] = "523"
	m11[6] = "623"
	/*
		   注意重点:
		   	以下方法可以判断该值是否存在,如果不存在,b为false,v为空
									        存在,b为true,v为值
	*/
	v, b := m11[1001]
	fmt.Printf("%s", v)
	fmt.Println(b)


//输出结果 :false

19.打印空字符串 %q

20.map 的delete ,如果该值不存在,不会报错。这是map的特性

21.结构体传参:

1.将结构体变量拷贝一份,传递。--几乎不用。内存消耗大,效率低
2.将结构体变量地址值,传递(传引用)。---使用频率非常高
3.unSafe.Sizeof(变量名)-->此种类型的变量所占用的内存空间大小
4.unSafe.Sizeof(指针):不管何总类型的指针,在64位操作系统下,大小一致。均为8字节!!!

22.结构体变量的比较:

  

1.比较:只能使用==和!=  不能> < >= <= ...
2.相同结构体类型(成员变量的类型、个数、顺序一致)变量之间可以直接赋值(注意:如果顺序不一致,就认为不是同一个结构体)

23.结构体指针做函数返回值:

   

1.不能返回局部变量的地址值---局部变量保存栈帧上,函数调用结束后,栈帧释放。
                           局部变量的地址,不再受系统保护,随时可能分配给其他程序。
2.可以返回局部变量的值。

24.切片使用

// 代码
func test() {
   arr := []int{1, 2, 3, 4, 5, 6}
   i := 0
   fmt.Println("前:", arr)
   res := append(arr[:i], arr[i+1:]...)
   fmt.Println("后:", arr)
   fmt.Println("res:", res)
}

//  期望的输出
前: [1 2 3 4 5 6]
后: [2 3 4 5 6]
res: [2 3 4 5 6]


// 正式的输出结果

前: [1 2 3 4 5 6]
后: [2 3 4 5 6 6]  // 差异点,多出了最后一个6
res: [2 3 4 5 6]

// 原因分析,为什么会多出一个6呢?因为执行append操作时,默认是第二个参数复制到第一个参数后。但是因为操作的是同一个slice,所以直接将第个参数直接覆盖原slice的前面5个值(2,3,4,5,6),最后一个值,就是slice自己本身的。

<think>好的,我现在需要帮用户解决“新手编程学习思路”的问题。首先,我得想想用户可能的需求是什么。用户是编程新手,所以需要从最基础的开始,逐步引导他们。可能需要先确定学习目标,然后选择合适的语言,接着是基础语法,再到项目实践,最后是持续提升。 用户可能没有明确的方向,不知道该从哪里下手。所以第一步应该建议他们明确目标,比如开发网站、做数据分析或者游戏开发。不同的目标对应不同的语言选择,比如Python适合数据分析,JavaScript适合网页开发。这点很重要,因为选择适合的语言能增加学习的动力。 接下来是学习编程基础。变量、数据类型、控制结构这些是必须的,但新手可能会觉得枯燥。需要强调循序渐进,免一开始就接触复杂的概念,比如面向对象或者设计模式。同时,要提醒他们注意代码规范,比如命名规范和注释,这对以后协作和可读性很重要。 然后是项目实践。新手可能不知道如何将所学应用到实际中,应该鼓励他们从小项目开始,比如计算器或待办事项列表,这样可以巩固知识。同时,参与开源项目或团队协作也是提升的好方法,但可能需要一定的引导。 遇到问题怎么办?调试和解决问题是关键能力。要教会他们使用搜索引擎、官方文档和社区资源,比如Stack Overflow。调试工具的使用也是需要练习的,比如断点和日志输出。 持续学习方面,推荐书籍和在线课程,但要选择适合新手的资源。参与技术社区可以保持学习热情,了解行业动态。算法和数据结构是进阶的基础,但可能需要一定的编程基础后再深入。 最后,要提醒免常见的误区,比如不要追求完美代码,不要死记硬背,也不要过早接触复杂领域。保持耐心和坚持是关键。 现在要确保结构清晰,分点说明,使用用户易懂的语言。同时,按照系统指令,数学公式用$...$,独立公式用$$...$$,不过这个问题可能涉及数学较少,但如果有例子的话需要注意格式。比如在讲解算法复杂度时可能会提到$O(n)$,这时要用正确的格式。 检查是否有LaTeX语法错误,确保中文回答,不使用Markdown格式。最后,总结整个思路,让用户有一个明确的路径,从目标到实践,再到提升,逐步成长。</think>编程新手学习可遵循以下分阶思路(附知识地图): 一、明确学习目标(先导阶段) $$学习方向 = \begin{cases} Web开发 \rightarrow JavaScript/Python \\ 移动开发 \rightarrow Kotlin/Swift \\ 数据分析 \rightarrow Python/R \\ 游戏开发 \rightarrow C#/C++ \\ 系统编程 \rightarrow Go/Rust \end{cases}$$ 建议优先选择Python或JavaScript作为入门语言,因其语法简洁且应用场景广泛 二、掌握编程基础(筑基阶段) 1. 核心语法三要素: - 变量与数据类型:理解$变量 = 存储容器 + 类型标识$ - 控制结构:掌握条件语句(if-else)、循环语句(for/while) - 函数机制:理解$输出 = f(输入)$的映射关系 2. 代码规范训练: - 命名规范:userCount优于a - 注释规范:关键逻辑需添加说明 - 缩进规则:严格遵循语言约定 三、项目实践驱动(实战阶段) 推荐实践路线: ``` 命令行工具 → 简单网页 → 数据库应用 → API开发 → 完整项目 ``` 典型入门项目: - 温度单位转换器(变量运用) - 质数判断程序(循环逻辑) - 待办事项管理系统(CRUD操作) 四、调试与问题解决(关键能力) 1. 错误处理三部曲: 1. 阅读错误信息:定位报错位置 2. 最小化复现:构造简单测试用例 3. 分层验证:使用print/debugger逐层排查 2. 资源利用策略: - 官方文档 > 技术博客 > 视频教程 - Stack Overflow搜索技巧:使用[标签]+关键词 五、持续提升路径(进阶阶段) 1. 计算机科学基础: - 算法复杂度分析(理解$O(n)$等表示法) - 数据结构:掌握链表、栈、队列的实现 $$二叉树深度 = \max(左子树深度, 右子树深度) + 1$$ 2. 工程化能力培养: - 本控制(Git基础) - 单元测试编写 - 持续集成概念 六、指南 1. 免过早深入: - 设计模式 - 框架源码 - 系统架构 2. 克服典型障碍: - "教程地狱":看3小时教程不如写30分钟代码 - "完美主义":先实现再优化 - "知识焦虑":建立个人知识图谱 建议每周保持10小时有效学习,3个月后可完成从0到1的跨越。关键路径:基础语法(2周)→小程序开发(4周)→完整项目(6周)→迭代优化(持续)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值