函数的技巧和难点
语言环境搭建
- 目录分类
- pkg:包目录
- bin:编译后的可执行二进制文件目录
- src:源代码目录
- 项目组织方式:namespace
- 在src目录下存放源代码
- 顶层目录:自己的域名 elepnt.com
- 次级目录:自己GitHub上的用户名,即作者:Crisv;或者在公司分组时用组名,如:前端组、后端组、基础架构组
- 项目名
- 模块a
- 模块b
- 模块c
- 项目名
- 次级目录:自己GitHub上的用户名,即作者:Crisv;或者在公司分组时用组名,如:前端组、后端组、基础架构组
- 示例 --------
- go的环境搭建环境搭建
- gopath 用来存放以后所写代码的目录
- 目录分类
- pkg:包目录
- bin:编译后的可执行二进制文件目录
- src:源代码目录
- 目录分类
- gopath设置:".zshrc" or ".bash_profile"
- goroot:bin
- gomod
- gopath 用来存放以后所写代码的目录
工程管理:包和模块 package module
- 开发流程
- 分析需求,列出功能清单,需求说明 30%
- 懂业务
- 懂技术
- 结果:需求分析报告
- 设计程序功能,写功能规格书和技术规格书 20%
- 项目经理或架构师
- 技术(开发语言):
- 操作系统,框架
- 数据库:数据库设计
- 选人
- 结果:设计文档
- 界面原型Axure
- 代码实现,进入开发与测试迭代
- 软件工程师【码农】
- 实现各个模块
- 调试和性能等专项测试 20%
- 软件测试工程师
- 黑盒测试
- 白盒测试(懂代码)
- 灰盒测试
- 部署上线
- 实施工程师
- 运行维护和营销
- 用户发现问题
- 分析需求,列出功能清单,需求说明 30%
- Dev 开发环境、QA 测试环境、预发布环境、发布环境、生产环境、灰度(金丝雀发布)环境
- 目标和方法论:--------
- 模块化:是从代码的角度进行分析的单独的文件,由一个,或多个函数,类组成。 把一些可复用的代码,抽离为单个模块,便于项目的维护和开发。
- 模块化工具
- webpack
- rollup
- 模块化工具
- 组件化:是从UI界面的角度进行分析的把一些可复用的UI界面,抽离为单个组件,便于项目的维护和开发。 vue.js 通过.vue文件创建组件 template 结构 script 行为 style 样式 三部分组成一个组件 react有组件化概念,一切都是由JS表现的。
- 可根据模块分文件
- 以上按需分配,组合成完成制定功能的程序。
- 以包作为管理单位
- 每组文件都会称为一个包
- 放在同一个文件夹里
- 用import "" 导入import ( "fmt" "os" )
- 导入的包,必须使用
- 给包名起别名
- 忽略包
- import _ "fmt"
- 用包的init函数
- main函数和init函数
- 打包 package
- 一个程序只能有一个main包,有且只有一个入口地址,main()函数,作为函数的入口
- 同一个目录里文件的包名必须一样
- 同一个目录,调用别的函数,直接调用即可,无需包名。
- 不同目录,包名不一样
- 调用不同包的函数:包名.函数名()
- 调用包里的函数必须是共有函数
匿名函数与闭包、延时调用
普通函数:使用传统的局部变量,函数调用时才分配空间,调用完,自动释放。
匿名函数(没有名字的函数):它不关心这些捕获的变量和常量是否已经超出作用域,只要还在使用它,这些变量还会存在。
func(i, j int) (max, min int){ } (10, 20)
闭包以引用方式传递外部参数。就是可以使用一个外部变量的引用。
-
函数可以作为返回值
-
函数内部查找变量的顺序,先在自己内部找,找不到往外层找
-
闭包 = 函数 + 外部变量的引用
情景应用:
-
设计模块化框架使用
-
函数根据不同的参数处理不同的业务
-
首先接受一个参数来决定定义出来的匿名函数根据所传参数做什么特定功能
-
再传入参数实现真正的功能
-
-
缓存函数执行的结果,供下一次执行时使用
-
Example:
Open: Pasted image 20240813170557.png
Open: Pasted image 20240813170621.png
Open: Pasted image 20240813170644.png
回调函数:
- 函数有一个参数是函数类型
- 把调配和实际处理分开
- 调用同一个接口,可以实现不同的表现
- 只要符合该接口的规定即可
泛型:数组等类型定义时,数组内的元素的类型只是规定一个类型的占位符。而在实例化的时候给定具体的类型。
引用,还是值拷贝
- 野引用,悬挂指针
- 同步,锁
- 内存泄露
- 作用域
- 生命周期
- 结构体方法所传进来参数的生命周期要>=结构体的生命周期
- move
递归 recursion
并发 routine、多线程thread
串行、并行、并发的基础知识
-
串行:单一执行流程,计算机只能一个任务一个任务的处理。缺点:效率低下,进程阻塞所带来的CPU资源的完全浪费。
-
并行:多进程、多线程。将cpu进行时间分片,轮询的执行。几个程序看起来是同时在运行,实际上每个时间片只有一个程序在运行。这样就解决了多进程/多线程的阻塞问题。
- 缺点:
- 多线程会有同步竞争,如锁、竞争资源冲突等。开发设计会变得更加复杂。
- 会有切换成本。进程/线程数量越多,切换成本就越大,越浪费。
- 多进程4GB、多线程4MB,占用内存会比较多
-
解决方案:众向分层,协程co-routine的提出
- 分为两层:
- 内核空间对应cpu的线程
- 用户空间对应协程 co-routine
- 如果内核空间的线程有N个,用户空间中的协程有M个,则线程和协程就形成M:N的关系
反射 reflect
在程序运行期对程序本身进行访问和修改的能力。 会造成程序运行效率低下。
Open: Pasted image 20240813170758.png
- 一般情况,当程序写完,所有的变量即已确定。但是在交互时,变量是在程序运行时,根据接收到的数据情况才能确定变量的类型。此时对变量的处理需要用到反射的技术,对本身进行修改。
- 程序在编译时,该变量被转换为内存地址,变量名不会被编译器写入到任何可执行部分。
- 在运行程序时,程序无法获取自身的信息。
- 反射的本质是在运行时得到对象的具体类型
- 允许程序操作任意类型的对象,运行时可以转换过来
- v := reflect.ValueOf()
- v := reflect.TypeOf()
- k := v.Kind()
- 传指针
- 得到的interface通用类型,再用stu, ok := iV.(Student)断言转回去
- 或者用switch语句判断所有可能的类型
- 通过反射设置变量的值:val.Elem().SetInt(100)
- 结构体反射
- 最佳实践:
- 反序列化 Unmarshal
- 空接口 interface
- 使用反射来遍历结构体的字段,调用结构体的方法,并获取结构体标签的值
- Method 方法
- Call 方法
- 适配器模式
- 用反射操作任意结构体
- 用反射来创建并操作结构体
异常处理 Exception handling
智能指针
- unique_ptr 独占内存,不共享
- shared_ptr 用引用计数的方式共享内存
- weak_ptr 不以引用计数的方式共享内存
函数的柯里化
其它
语法,逻辑,可能造成的错误检查
语法糖,去糖
匿名变量、匿名函数