Go Proxy
配置Go模块代理,否则要配置翻墙。
Goproxy.cn
IDE
个人推荐GoLand,IDEA使用习惯了。
基本代码结构
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
Go代码不需要在行后面加;
。
变量
格式
var 变量名 类型
, var age int = 1
跟Java和C不太一样,先变量名后类型。
也可以不指定变量类型,编译器会自动推导类型。
Go中的变量声明了一定要使用,否则会编译错误。
例如:
package main
import "fmt"
var age = 1
func main() {
fmt.Printf("%T", age)
}
// output: int
Go也支持批量声明变量,例如:
package main
import "fmt"
var (
age int
area float64
name string
)
func main() {
fmt.Printf("%T, %T, %T", age, area, name)
}
// output: int, float64, string
Go支持简短的变量初始化,用法:变量 := 初始化值
,有三个限制:
-
定义变量同时初始化 -
不能显示指定数据类型 -
只能用在函数内部
package main
import "fmt"
func main() {
i := 1
fmt.Println(i)
}
这种写法多用在函数内局部变量的声明初始化。
短变量声明也可以批量声明,例如:
package main
import "fmt"
func main() {
i, j := 1, 2
fmt.Printf("%d, %d", i, j)
}
并且多个短变量声明,只要至少有一个新声明的变量出现在左边,即使有变量名重复,也是不会报错的。
package main
import "fmt"
func main() {
i := 1
i := 2
fmt.Printf("%d, %d", i, i)
}
// output: no new variables on left side of :=
package main
import "fmt"
func main() {
i := 1
i, j := 2, 3
fmt.Printf("%d, %d", i, j)
}
// output: 2, 3
批量声明和多重赋值用起来还是比较方便的,比如交换变量的语法糖,使用Go的特性就非常简单:
package main
import "fmt"
func main() {
a, b := 1, 2
fmt.Printf("%d, %dn", a, b)
b, a = a, b
fmt.Printf("%d, %d", a, b)
}
// output
// 1, 2
// 2, 1
Go中还有一种特殊的变量,叫匿名变量,在使用多重赋值时,如果不需要接受值,可以使用。
匿名变量可以重复声明,但不可以单独用于声明。
例如可以忽略网络链接返回的错误:
package main
import (
"fmt"
"net"
)
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:80")
fmt.Println(conn)
}
source code:
// Examples:
// Dial("ip4:1", "192.0.2.1")
// Dial("ip6:ipv6-icmp", "2001:db8::1")
// Dial("ip6:58", "fe80::1%lo0")
//
// For TCP, UDP and IP networks, if the host is empty or a literal
// unspecified IP address, as in ":80", "0.0.0.0:80" or "[::]:80" for
// TCP and UDP, "", "0.0.0.0" or "::" for IP, the local system is
// assumed.
//
// For Unix networks, the address must be a file system path.
func Dial(network, address string) (Conn, error) {
var d Dialer
return d.Dial(network, address)
}
基本类型
-
bool
-
string
-
int
,大小随操作系统,一般占用4个字节,也可以指定大小,int8
、int16
、int32
、int64
-
uint
,无符号整数,uint8
、uint16
、uint32
、uint64
、uintptr
(指针) -
byte
-
rune
,int32
的别名,代表一个Unicode码
-
float32
、float64
-
complex64
、complex128
二进制的文件读写的时候,因为int
和uint
大小会受到机器影响,不要使用int
和uint
字符类型的定义方式:
var char byte = 'A'
var char byte = 65 // ASCII码
var char byte = 'x41' // 十六进制
var char byte = '101' // 八进制
Unicode使用需要在16进制前加u
(4字节) 或者U
(8字节)
作用域
三个类型:
-
函数内部定义——局部变量 -
函数外部定义——全局变量,全局变量声明必须用 var
声明,需要在外部包使用的全局变量首字母必须大写 -
函数中定义——函数参数(形参)
Go语言中全局变量和局部变量名称可以相同,但函数体中的局部变量优先级高。
import "fmt"
func main() {
a := 1
b := 2
fmt.Printf("%d + %d = %d", a, b, sum(a, b))
}
func sum(a, b int) int {
a = 10
b = 20
fmt.Printf("a=%d, b=%dn", a, b)
return a + b
}
// output:
// a=10, b=20
// 1 + 2 = 30
函数值传递时,是不会修改原值的,函数形参会在栈中复制一份新的变量。
字符串
声明方式:var name string = "二胖"
,如果使用反引号,会去除转义,按照原样输出。
Go语言原生支持UTF-8编码,Go中字符串可能根据需要单个占用1-4个字节,比如如果单个字符是ASCII码表中的只占1字节。
字符串是内存常量,声明之后不可变,底层是定长的字节数组,byte
和rune
字符类型组成字符串。
字符串的长度跟其他语言不太一样:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
name := "hnzhrh二胖"
fmt.Printf("%dn", len(name))
fmt.Printf("%d", utf8.RuneCountInString(name))
}
// output
// 12
// 8
len
函数获取到的是字节数组的长度,Unicode编码会占用多个字节(中文三个字节)所以结果是12。
字符串拼接可以直接使用+
,性能不高,也可以使用库方法。
package main
import (
"bytes"
"fmt"
)
func main() {
s1 := "hello "
s2 := "world"
var strBuilder bytes.Buffer
strBuilder.WriteString(s1)
strBuilder.WriteString(s2)
fmt.Printf("%s", strBuilder.String())
}
如果说想要获取字符串中的某个位置的中文,例如:
package main
import "fmt"
func main() {
str := "二胖"
fmt.Printf("%s", string([]rune(str)[1])) //先类型转换str位[]rune数组,再取1位置的转换成string
}
不能使用直接索引str[1]
,这样是取字节数组的位置1的字符。
unicode字符集只能使用for range
遍历,ASCII字符集可以使用for range
或者for
遍历。
package main
import "fmt"
func main() {
str1 := "hnzhrh"
str2 := "二胖"
// for 遍历
for i := 0; i < len(str1); i++ {
fmt.Printf("%c %d,", str1[i], i)
}
fmt.Println()
// for range 遍历
for i, char := range str1 {
fmt.Printf("%c %d,", char, i)
}
fmt.Println()
// for range 索引是字节数组的索引
for i, char := range str2 {
fmt.Printf("%c %d,", char, i)
}
}
// output
// h 0,n 1,z 2,h 3,r 4,h 5,
// h 0,n 1,z 2,h 3,r 4,h 5,
// 二 0,胖 3,
strings
包提供了很多常用的字符串操作。
字符串格式化占位符
-
%c
-
%T
,动态类型 -
%v
,值 -
%+v
,字段名+值 -
%d
-
%p
,十六进制指针 -
%f
-
%b
,二进制 -
%s
类型转换
Go语言不存在隐式转换,必须显示指定,类型B值 = typeB(类型A的值)
。
例如:
a := 5.0
b := int(a)
常用的字符串的类型转换可以借助包strconv
的函数进行。
常量
使用关键字const
定义,const 变量名 [type] = value
。
也可以批量声明多个常量:
const (
e = 2.7
pi = 3.14
)
批量声明常量,除了第一个外,其他常量右边的初始化表达式都可以省略,如果省略表示使用前面常量的初始化表达式,对应的类型也是一样的。
const (
a = 1
b
c = 2
d
)
// a b c d = 1 1 2 2
Go 有一个特殊的常量声明方式,iota
常量初始化生成器,用来生成一组相似规则初始化的常量,比如星期、月份等。
在第一个声明的常量所在的行,iota
的值会被置为0,然后后面再每一个有常量声明的行加1。
const (
SUNDAY = iota // 0
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY // 6
)
指针
Go的指针有两个核心概念:
-
类型指针,可以按地址传值,不能进行偏移和运算 -
切片,有指向起始数据的头指针、数据大小和容量组成
这样的好处是Go类型指针既拥有高效的访问速度,又避免了因为指针偏移导致非法修改数据的问题。
在Go中,指针如果没有初始化,默认值位nil
,使用&
前缀操作符来获取变量的内存地址,使用*
可以对指针进行取值。
package main
import "fmt"
func main() {
name := "erpang"
ptr := &name
fmt.Printf("%T %p, %s", ptr, ptr, *ptr)
}
// output
// *string 0xc000066250, erpang
Go还提供了一种指针声明方式:
ptr := new(string)
*ptr = "erpang"
通过指针可以进行函数的按址传递:
package main
import "fmt"
func main() {
a := 1
b := 2
fmt.Printf("%d + %d = %d", a, b, sum(&a, &b))
}
func sum(a, b *int) int {
*a = 10
*b = 20
fmt.Printf("a=%d, b=%dn", *a, *b)
return *a + *b
}
// output
// a=10, b=20
// 10 + 20 = 30
指针的一个小应用,获取命令行参数,Go中是通过flag形式--flag=value
形式。
package main
import (
"flag"
"fmt"
)
var dir = flag.String("dir", "", "文件目录地址")
func main() {
flag.Parse()
fmt.Printf("命令行参数dir: %s", *dir)
}
// 用命令行调用
go run test.go --dir="c:/"
// output
命令行参数dir: c:/
// 帮助文档
go run test.go --help
// out put
Usage of C:UsersADMINI~1AppDataLocalTempgo-build1673057279b001exetest.exe:
-dir string
文件目录地址
如此可以通过命令行参数注入一些配置信息,可以类比JVM参数理解。
类型别名和新类型定义
类型别名使用方式:type alias = Type
,别名在编译结束后会被替换
比如:type byte = uint8
新类型定义:type name type
比如:type age int
类型别名和新类型定义是不一样的,新类型定义会定义一种新类型,而别名不会。
package main
import "fmt"
func main() {
type age = int
var myAge age = 10
type length int
var myLength length = 20
fmt.Printf("%T, %T", myAge, myLength)
}
// output
int, main.length
Go由于只能显示转换类型,所以以下代码会报错
package main
import "fmt"
func main() {
type age = int // 别名
var myAge age = 10
type length int // 新类型
var myLength length = 20
fmt.Printf("%T, %T", myAge, myLength)
yourAge := 100
yourLength := 200
totalAge := myAge + yourAge // 别名类型相同,可以运算,相当于同类型
totalLength := myLength + yourLength // 类型不同,不能运算
fmt.Printf("%d, %d", totalAge, totalLength)
}
// output
.test.go:14:17: invalid operation: myLength + yourLength (mismatched types length and int)
原文始发于微信公众号(erpang coding):Golang基础知识一
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/37411.html