Golang基础知识一

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 := 12
 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 := 23
 fmt.Printf("%d, %d", i, j)
}
// output: 2, 3

批量声明和多重赋值用起来还是比较方便的,比如交换变量的语法糖,使用Go的特性就非常简单:

package main

import "fmt"

func main() {
 a, b := 12
 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个字节,也可以指定大小,int8int16int32int64
  • uint ,无符号整数,uint8uint16uint32uint64uintptr (指针)
  • byte
  • runeint32 的别名,代表一个Unicode码
  • float32float64
  • complex64complex128

二进制的文件读写的时候,因为intuint 大小会受到机器影响,不要使用intuint

字符类型的定义方式:

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字节。

字符串是内存常量,声明之后不可变,底层是定长的字节数组,byterune 字符类型组成字符串。

字符串的长度跟其他语言不太一样:

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

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!