go语言学习 - 指针

前置知识 在编程中,一个内存地址用来定位一段内存。 通常地,一个内存地址用一个操作系统原生字(native word)来存储。 一个原生字在32位操作系统上占4个字节,在64位操作系统上占8个字节。 所以,32位操作系统上的理论最大支持内存容量为4GB(1GB == 230字节),64位操作系统上的理论最大支持内存容量为264Byte,即16EB(EB:艾字节,1EB == 1024PB, 1PB == 1024TB, 1TB == 1024GB)。 内存地址的字面形式常用整数的十六进制字面量来表示,比如0x1234CDEF。 以后我们常简称内存地址为地址。 指针是Go中的一种类型分类(kind)。 一个指针可以存储一个内存地址;从地址通常为另外一个值的地址。 和C指针不一样,为了安全起见,Go指针有很多限制,只有取值和取址操作。 指针取址 go语言中使用&+变量来获取变量的地址 package main import "fmt" func main() { var a int32 = 45 var b int32 = a fmt.Println("a的指针是:", &a) fmt.Println("b的指针是:", &b) } 指针变量 保存上面的&a &b这种指针数据的变量被称为指针变量,指针变量类型用*指针源值数据类型表示 package main import "fmt" func main() { var a int32 = 45 var b int32 = a fmt.Println("a的指针是:", &a) fmt.Println("b的指针是:", &b) var x *int32 = &a fmt.Println("x是:", x) } 指针取值 go语言中使用+指针变量来获取指针的值* ...

February 23, 2023 · 1 min · 117 words · Norman Wang

go语言学习 - 协程、延迟函数以及恐慌和恢复

协程(goroutine) 协程是go语言内部唯一实现程序并发的方式,go不支持创建系统线程 在Go中,开启一个新的协程是非常简单的。 我们只需在一个函数调用之前使用一个go关键字,即可让此函数调用运行在一个新的协程之中。 当此函数调用退出后,这个新的协程也随之结束了。 // 在下面的例子程序中,主协程创建了两个新的协程,由于主协程Sleep 2秒。所以两个协程内容没有执行完。 package main import ( "log" "math/rand" "time" ) func SayGreetings(greeting string, times int) { for i := 0; i < times; i++ { log.Println(greeting) d := time.Second * time.Duration(rand.Intn(5)) / 2 time.Sleep(d) } } func main() { rand.Seed(time.Now().UnixNano()) log.SetFlags(0) go SayGreetings("hi!", 10) go SayGreetings("Hello!", 10) time.Sleep(2 * time.Second) } 并发同步 使用通道技术可以实现并发同步,sync标准库提供的WaitGroup可以很简单实现这一点 ...

February 21, 2023 · 2 min · 355 words · Norman Wang

go语言学习 - 流程控制

if-else条件分支控制代码块 rand.Seed(time.Now().UnixNano()) var n = rand.Int() if n%2 == 0 { fmt.Println(n, "是一个偶数") } else { fmt.Println(n, "是一个奇数") } if a := rand.Int(); a%2 != 0 { fmt.Println(a, "是一个奇数") } else { fmt.Println(a, "是一个偶数") } for循环代码块 for i := 0; i < 10; i++ { if i == 4 { continue } fmt.Println(i) } for i := 0; i < 10; i++ { if i == 4 { break } fmt.Println(i) } switch-case流程控制代码块 y := rand.Intn(100) % 5 fmt.Println(y) switch y { case 0, 1: fmt.Println("0 1y =", y) fallthrough case 2, 3: fmt.Println("2 3y =", y) fallthrough case 4, 5: fmt.Println("4 5y =", y) fallthrough default: fmt.Println("default y =", y) } goto跳转语句和跳转标签声明 package main import "fmt" func main() { i := 0 Next: // 跳转标签声明 fmt.Println(i) i++ if i < 5 { goto Next // 跳转 } }

February 20, 2023 · 1 min · 139 words · Norman Wang

go语言学习 - 函数声明和调用

函数声明 golang函数声明和其他语言类似,关键字为func。只要有参数和返回值就必须指定类型,一个函数可以有多个参数和返回值 package main func add(a int32, b int32) (c int32) { return a + b } func reduce(a int32, b int32) int32 { return a - b } func square(a int64, b int64) (c int64, d int64) { c = a * a d = b * b return } func main() {} 函数调用 golang函数调用和其他语言类似,用小括号扩起来,括号里面是参数 package main func add(a int32, b int32) (c int32) { return a + b } func reduce(a int32, b int32) int32 { return a - b } func square(a int64, b int64) (c int64, d int64) { c = a * a d = b * b return } func main() { c := add(5, 7) e, f := square(7, 5) print("5 + 7 = ", c, "\n") print("7,5 square is ", e, "\t", f, "\n") } 匿名函数 匿名函数是没有函数名的特殊函数,一个匿名函数在定义后可以被立即调用。go中所有函数都可以访问其作用域中变量,这样的函数称为闭包 ...

February 19, 2023 · 1 min · 182 words · Norman Wang

go语言学习 - 运算符

算术运算符 二元运算符 字面形式 名称 解释 + 加法 两个运算数的类型必须相同并且为基本数值类型 - 减法 两个运算数的类型必须相同并且为基本数值类型 * 乘法 两个运算数的类型必须相同并且为基本数值类型 / 除法 两个运算数的类型必须相同并且为基本数值类型 % 取余 两个运算数的类型必须相同并且为基本整数数值类型 位运算符 字面形式 名称 & 位与 ^ 异或 &^ 清位 « 左移位 » 右移位 一元运算符 字面形式 名称 解释 + 取正数 +n等价于0 + n - 取负数 -n等价于0 - n ^ 位反 op=运算符 var a, b int8 = 3, 5 a += b println(a) // 8 a *= a println(a) // 64 a /= b println(a) // 12 a %= b println(a) // 2 b <<= uint(a) println(b) // 20 自增/自减运算符 go语言自增和自减运算符没有返回值 ...

February 16, 2023 · 2 min · 264 words · Norman Wang

go语言学习 - 关键字和标识符

关键字 关键字是一些特殊的用来帮助编译器理解和解析源代码的单词,程序员不能用作变量/常量等定义。截止到go 1.19版本,go语言中有25个关键字 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var 这些关键字可以分为四组 const var func import package type 用来声明各种代码元素 chan interface map struct 用做 一些组合类型的字面表示 break case continue default else fallthrough for goto if range return select switch 用在流程控制语句中 defer go 也可以看作是流程控制关键字, 但它们有一些特殊的作用 标识符 一个标识符是一个以Unicode字母或者_开头并且完全由Unicode字母和Unicode数字组成的单词。标识符被用作类型名、变量名、常量名、跳转标签、包名和包的引入名 合法的标识符 Player_9 DoSomething VERSION Ĝo Π 非法的标识符 ...

February 14, 2023 · 1 min · 83 words · Norman Wang

go语言学习 - 基本数据类型

基本数据类型介绍 类型就是值的模版,值必须满足这个模版,不然就会报错 Go支持如下内置基本类型: 一种内置布尔类型:bool。 11种内置整数类型:int8、uint8、int16、uint16、int32、uint32、int64、uint64、int、uint和uintptr。 两种内置浮点数类型:float32和float64。 两种内置复数类型:complex64和complex128。 一种内置字符串类型:string。 注意: int8 int16后面的数字代表此类型的容量/尺寸。8就是8位/bit。 uint8 u开头代表非负整数。uint8范围就是0~255,int8范围-128~127. uintptr、int以及uint类型的值的尺寸依赖于具体编译器实现。 通常地,在64位的架构上,int和uint类型的值是64位的;在32位的架构上,它们是32位的。 编译器必须保证uintptr类型的值的尺寸能够存下任意一个内存地址。 一个complex64复数值的实部和虚部都是float32类型的值。 一个complex128复数值的实部和虚部都是float64类型的值。 类型声明 我们可以使用type声明定义更多自定义布尔和字符串类型。 // 一些类型定义声明 type status bool // status和bool是两个不同的类型,但是最终结果都是bool type MyString string // MyString和string是两个不同的类型 type Id uint64 // Id和uint64是两个不同的类型 type real float32 // real和float32是两个不同的类型 // 一些类型别名声明 type boolean = bool // boolean和bool表示同一个类型 type Text = string // Text和string表示同一个类型 type U8 = uint8 // U8、uint8和 byte表示同一个类型 type char = rune // char、rune和int32表示同一个类型 零值 每种类型都有一个零值。一个类型的零值可以看作是此类型的默认值。 ...

February 14, 2023 · 1 min · 74 words · Norman Wang

go语言学习 - 变量和常量

变量 变量的定义和赋值有多种方式 方式1 只定义不赋值,默认为0 package main func main() { var a int println("a = %d\n", a) } 方式2 package main func main() { var a int = 3 println("a = %d\n", a) } 方式3 忽略类型,go会自己推断 package main func main() { var a = 3 println("a = %d\n", a) } 方式4 忽略var关键字 package main func main() { a := 2 println("a = %d\n", a) } 方式5 多变量声明类似于单变量声明,但是忽略var只能在函数内使用 ...

February 13, 2023 · 1 min · 183 words · Norman Wang

记录Ubuntu 20.04 Server 环境配置及软件安装

服务器是去年双11买的,腾讯轻量应用服务器。2核4G、80G硬盘、8Mbps、流量限制1200GB/月;淘宝买的3年139元;买来就当玩玩吧!!! 更新软件源 更新软件源是必备操作,最好在安装软件之前都要更新一遍。 sudo apt update sudo apt-get update 安装多版本nodejs 注:apt-get安装的nodejs不包括npm,需要分别安装;安装的版本也不是最新,所以需要用n模块安装最新版本nodejs 通过apt-get安装nodejs npm sudo apt-get install nodejs sudo apt-get install npm 安装n模块 sudo npm i -g n 安装最新稳定版nodejs sudo n lts 安装特定版本nodejs sudo n 10.16.0 安装docker docker安装参考官方文档即可,以下内容均来自官方文档 卸载之前版本的docker sudo apt-get remove docker docker-engine docker.io containerd runc 安装依赖软件 sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release 添加docker官方GPG key curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 设置repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 安装docker sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin 验证docker是否安装成功 sudo docker run hello-world 安装Nextcloud私有网盘系统 Nextcloud是成熟的开源网盘系统,有完善的权限管理系统。有全平台客户端以及web页面。一行命令就可以通过docker安装 ...

May 22, 2022 · 1 min · 181 words · Norman Wang

建e网VR全景图片的获取思路

年前,我接到大学朋友的一个移动端官网项目。项目就是完全复刻另外一个网站A,好在网站A功能超级简单,前端技术栈是jq,整个网站只有两个难点。 有一个提交表单功能 有一个VR展示页面 对于第一个问题,我就找了个开源后台项目Lin cms,搭建了一套写了一个模块。第二个问题就有意思了,网站A使用的是叫建e网生成的VR页面。然后iframe且套到网页上。现在有两种方案;第一种,自己写VR页面,但是我就想赚快钱,不想动脑筋,所以否定了。第二种,用自己的建e网账号制作一个一摸一样的VR页面,替换iframe地址,但是我又没有生成VR页面所需要的六面图片,甲方这里也没有。那我只能用F12大法了。 在VR页面右下角三个控键上右键,点击检查 切换到network -> img,并刷新网页 这时你会看到lx_x_x_x命名的图片,这些其实就是VR图片 更具我的判断,命名含义如下 第一位l固定值 第二位目前只有1 2两种情况代表着分辨率;1为一倍分辨率(1024*1024),2为2倍分辨率 第三位代表方向 缩写 全写 中文 l left 左 f forward 前 u up 上 r right 右 b back 后 p down 下 第四位和第五位为排序字段;如果第二位为1代表着是1倍分辨率,这时第五 六位都是1,也就是说每一面图片都是一张完整图,但是这样的图片分辨率低,不建议使用。如果第二位是2代表2倍分辨率,这时每一面图片由四张组成,他们的拼接顺序是,请看下方图片。由于每张图片分辨率是1024*1024,拼接后的分辨率就是2048*2048 依次把六个面图片,都拼接好,这样就得到高分辨率可用于VR中的图片了

February 28, 2022 · 1 min · 39 words · Norman Wang