Golang语法、技巧和窍门

在这里插入图片描述

Golang简介

  • 命令式语言
  • 静态类型
  • 语法标记类似于C(但括号较少且没有分号),结构类似Oberon-2
  • 编译为本机代码(没有JVM)
  • 没有类,但有带有方法的结构
  • 接口
  • 没有实现继承。不过有type嵌入。
  • 函数是一等公民
  • 函数可以返回多个值
  • 支持闭包
  • 指针,但没有指针算术
  • 内置并发原语:Goroutines和Channels

基本语法

你好,世界

文件 hello.go

package mainimport "fmt"func main() {fmt.Println("Hello Go")
}
$ go run hello.go

运算符

算术运算符
运算符描述
+加法
-减法
*乘法
/除法
%取余
&位与
``
^位异或
&^位清除(非)
<<左移
>>右移
比较运算符
运算符描述
==等于
!=不等于
<小于
<=小于等于
>大于
>=大于等于
逻辑运算符
运算符描述
&&逻辑与
`
!逻辑非
其他
运算符描述
&取地址 / 创建指针
*解引用指针
<-发送 / 接收操作符(见下面的‘通道’部分)

声明

类型在标识符之后!

var foo int // declaration without initialization
var foo int = 42 // declaration with initialization
var foo, bar int = 42, 1302 // declare and init multiple vars at once
var foo = 42 // type omitted, will be inferred
foo := 42 // shorthand, only in func bodies, omit var keyword, type is always implicit
const constant = "This is a constant"// iota can be used for incrementing numbers, starting from 0
const (_ = iotaabc = 1 << iotad
)fmt.Println(a, b) // 1 2 (0 is skipped)fmt.Println(c, d) // 8 16 (2^3, 2^4)

函数

// a simple function
func functionName() {}// function with parameters (again, types go after identifiers)
func functionName(param1 string, param2 int) {}// multiple parameters of the same type
func functionName(param1, param2 int) {}// return type declaration
func functionName() int {return 42
}// Can return multiple values at once
func returnMulti() (int, string) {return 42, "foobar"
}
var x, str = returnMulti()// Return multiple named results simply by return
func returnMulti2() (n int, s string) {n = 42s = "foobar"// n and s will be returnedreturn
}
var x, str = returnMulti2()
函数作为值和闭包
func main() {// assign a function to a nameadd := func(a, b int) int {return a + b}// use the name to call the functionfmt.Println(add(3, 4))
}// Closures, lexically scoped: Functions can access values that were
// in scope when defining the function
func scope() func() int{outer_var := 2foo := func() int { return outer_var}return foo
}func another_scope() func() int{// won't compile because outer_var and foo not defined in this scopeouter_var = 444return foo
}// Closures
func outer() (func() int, int) {outer_var := 2inner := func() int {outer_var += 99 // outer_var from outer scope is mutated.return outer_var}inner()return inner, outer_var // return inner func and mutated outer_var 101
}
可变参数函数
func main() {fmt.Println(adder(1, 2, 3)) 	// 6fmt.Println(adder(9, 9))	// 18nums := []int{10, 20, 30}fmt.Println(adder(nums...))	// 60
}// By using ... before the type name of the last parameter you can indicate that it takes zero or more of those parameters.
// The function is invoked like any other function except we can pass as many arguments as we want.
func adder(args ...int) int {total := 0for _, v := range args { // Iterates over the arguments whatever the number.total += v}return total
}

内置类型

boolstringint  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptrbyte // alias for uint8rune // alias for int32 ~= a character (Unicode code point) - very Vikingfloat32 float64complex64 complex128

所有Go的预声明标识符都定义在builtin包中。

类型转换

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)// alternative syntax
i := 42
f := float64(i)
u := uint(f)

  • 在每个源文件的顶部声明包
  • 可执行文件位于main包中
  • 约定:包的名称等于导入路径的最后一个部分(导入路径math/rand => 包rand
  • 大写标识符:导出的(可以从其他包中访问)
  • 小写标识符:私有的(不能从其他包中访问)

控制结构

判断
func main() {// Basic oneif x > 10 {return x} else if x == 10 {return 10} else {return -x}// You can put one statement before the conditionif a := b + c; a < 42 {return a} else {return a - 42}// Type assertion inside ifvar val interface{} = "foo"if str, ok := val.(string); ok {fmt.Println(str)}
}
循环
    // There's only `for`, no `while`, no `until`for i := 1; i < 10; i++ {}for ; i < 10;  { // while - loop}for i < 10  { // you can omit semicolons if there is only a condition}for { // you can omit the condition ~ while (true)}// use break/continue on current loop// use break/continue with label on outer loop
here:for i := 0; i < 2; i++ {for j := i + 1; j < 3; j++ {if i == 0 {continue here}fmt.Println(j)if j == 2 {break}}}there:for i := 0; i < 2; i++ {for j := i + 1; j < 3; j++ {if j == 1 {continue}fmt.Println(j)if j == 2 {break there}}}
条件
    // switch statementswitch operatingSystem {case "darwin":fmt.Println("Mac OS Hipster")// cases break automatically, no fallthrough by defaultcase "linux":fmt.Println("Linux Geek")default:// Windows, BSD, ...fmt.Println("Other")}// as with for and if, you can have an assignment statement before the switch valueswitch os := runtime.GOOS; os {case "darwin": ...}// you can also make comparisons in switch casesnumber := 42switch {case number < 42:fmt.Println("Smaller")case number == 42:fmt.Println("Equal")case number > 42:fmt.Println("Greater")}// cases can be presented in comma-separated listsvar char byte = '?'switch char {case ' ', '?', '&', '=', '#', '+', '%':fmt.Println("Should escape")}

数组, 切片, 遍历

数组
var a [10]int // declare an int array with length 10. Array length is part of the type!
a[3] = 42     // set elements
i := a[3]     // read elements// declare and initialize
var a = [2]int{1, 2}
a := [2]int{1, 2} //shorthand
a := [...]int{1, 2} // elipsis -> Compiler figures out array length
切片
var a []int                              // declare a slice - similar to an array, but length is unspecified
var a = []int {1, 2, 3, 4}               // declare and initialize a slice (backed by the array given implicitly)
a := []int{1, 2, 3, 4}                   // shorthand
chars := []string{0:"a", 2:"c", 1: "b"}  // ["a", "b", "c"]var b = a[lo:hi]	// creates a slice (view of the array) from index lo to hi-1
var b = a[1:4]		// slice from index 1 to 3
var b = a[:3]		// missing low index implies 0
var b = a[3:]		// missing high index implies len(a)
a =  append(a,17,3)	// append items to slice a
c := append(a,b...)	// concatenate slices a and b// create a slice with make
a = make([]byte, 5, 5)	// first arg length, second capacity
a = make([]byte, 5)	// capacity is optional// create a slice from an array
x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // a slice referencing the storage of x
数组和切片的操作

len(a) 返回数组/切片的长度。这是一个内置函数,而不是数组的属性/方法。

// loop over an array/a slice
for i, e := range a {// i is the index, e the element
}// if you only need e:
for _, e := range a {// e is the element
}// ...and if you only need the index
for i := range a {
}// In Go pre-1.4, you'll get a compiler error if you're not using i and e.
// Go 1.4 introduced a variable-free form, so that you can do this
for range time.Tick(time.Second) {// do it once a sec
}

哈希表

m := make(map[string]int)
m["key"] = 42
fmt.Println(m["key"])delete(m, "key")elem, ok := m["key"] // test if key "key" is present and retrieve it, if so// map literal
var m = map[string]Vertex{"Bell Labs": {40.68433, -74.39967},"Google":    {37.42202, -122.08408},
}// iterate over map content
for key, value := range m {
}

结构体

Go中没有类,只有结构体。结构体可以拥有方法。

// A struct is a type. It's also a collection of fields// Declaration
type Vertex struct {X, Y float64
}// Creating
var v = Vertex{1, 2}
var v = Vertex{X: 1, Y: 2} // Creates a struct by defining values with keys
var v = []Vertex{{1,2},{5,2},{5,5}} // Initialize a slice of structs// Accessing members
v.X = 4// You can declare methods on structs. The struct you want to declare the
// method on (the receiving type) comes between the the func keyword and
// the method name. The struct is copied on each method call(!)
func (v Vertex) Abs() float64 {return math.Sqrt(v.X*v.X + v.Y*v.Y)
}// Call method
v.Abs()// For mutating methods, you need to use a pointer (see below) to the Struct
// as the type. With this, the struct value is not copied for the method call.
func (v *Vertex) add(n float64) {v.X += nv.Y += n
}

匿名结构体: 比使用 map[string]interface{} 更经济和更安全。

point := struct {X, Y int
}{1, 2}

指针

p := Vertex{1, 2}  // p is a Vertex
q := &p            // q is a pointer to a Vertex
r := &Vertex{1, 2} // r is also a pointer to a Vertex// The type of a pointer to a Vertex is *Vertexvar s *Vertex = new(Vertex) // new creates a pointer to a new struct instance

接口

// interface declaration
type Awesomizer interface {Awesomize() string
}// types do *not* declare to implement interfaces
type Foo struct {}// instead, types implicitly satisfy an interface if they implement all required methods
func (foo Foo) Awesomize() string {return "Awesome!"
}

嵌入

Go中没有子类化。相反,有接口和结构体嵌入。

// ReadWriter implementations must satisfy both Reader and Writer
type ReadWriter interface {ReaderWriter
}// Server exposes all the methods that Logger has
type Server struct {Host stringPort int*log.Logger
}// initialize the embedded type the usual way
server := &Server{"localhost", 80, log.New(...)}// methods implemented on the embedded struct are passed through
server.Log(...) // calls server.Logger.Log(...)// the field name of the embedded type is its type name (in this case Logger)
var logger *log.Logger = server.Logger

错误

Go中没有异常处理。相反,可能产生错误的函数只是声明了一个额外的返回值,类型为error。这是error接口:

// The error built-in interface type is the conventional interface for representing an error condition,
// with the nil value representing no error.
type error interface {Error() string
}

这是一个示例:

func sqrt(x float64) (float64, error) {if x < 0 {return 0, errors.New("negative value")}return math.Sqrt(x), nil
}func main() {val, err := sqrt(-1)if err != nil {// handle errorfmt.Println(err) // negative valuereturn}// All is good, use `val`.fmt.Println(val)
}

并发

协程

Goroutines是轻量级线程(由Go管理,而不是操作系统线程)。go f(a, b)启动一个新的goroutine来运行f(假设f是一个函数)。

// just a function (which can be later started as a goroutine)
func doStuff(s string) {
}func main() {// using a named function in a goroutinego doStuff("foobar")// using an anonymous inner function in a goroutinego func (x int) {// function body goes here}(42)
}

通道

ch := make(chan int) // create a channel of type int
ch <- 42             // Send a value to the channel ch.
v := <-ch            // Receive a value from ch// Non-buffered channels block. Read blocks when no value is available, write blocks until there is a read.// Create a buffered channel. Writing to a buffered channels does not block if less than <buffer size> unread values have been written.
ch := make(chan int, 100)close(ch) // closes the channel (only sender should close)// read from channel and test if it has been closed
v, ok := <-ch// if ok is false, channel has been closed// Read from channel until it is closed
for i := range ch {fmt.Println(i)
}// select blocks on multiple channel operations, if one unblocks, the corresponding case is executed
func doStuff(channelOut, channelIn chan int) {select {case channelOut <- 42:fmt.Println("We could write to channelOut!")case x := <- channelIn:fmt.Println("We could read from channelIn")case <-time.After(time.Second * 1):fmt.Println("timeout")}
}
通道原理
  • 向空通道发送会永远阻塞

    var c chan string
    c <- "Hello, World!"
    // fatal error: all goroutines are asleep - deadlock!
    
  • 从空通道接收会永远阻塞。

    var c chan string
    fmt.Println(<-c)
    // fatal error: all goroutines are asleep - deadlock!
    
  • 向已关闭的通道发送会引发恐慌。

    var c = make(chan string, 1)
    c <- "Hello, World!"
    close(c)
    c <- "Hello, Panic!"
    // panic: send on closed channel
    
  • 从已关闭的通道接收会立即返回零值。

    var c = make(chan int, 2)
    c <- 1
    c <- 2
    close(c)
    for i := 0; i < 3; i++ {fmt.Printf("%d ", <-c)
    }
    // 1 2 0
    

打印

fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ") // basic print, plus newline
p := struct { X, Y int }{ 17, 2 }
fmt.Println( "My point:", p, "x coord=", p.X ) // print structs, ints, etc
s := fmt.Sprintln( "My point:", p, "x coord=", p.X ) // print to string variablefmt.Printf("%d hex:%x bin:%b fp:%f sci:%e",17,17,17,17.0,17.0) // c-ish format
s2 := fmt.Sprintf( "%d %f", 17, 17.0 ) // formatted print to string variablehellomsg := `"Hello" in Chinese is 你好 ('Ni Hao')"Hello" in Hindi is नमस्ते ('Namaste')
` // multi-line string literal, using back-tick at beginning and end

反射

类型切换

类型切换类似于常规的switch语句,但类型切换中的情况指定要与给定接口值持有的值的类型进行比较的类型,而不是值。

func do(i interface{}) {switch v := i.(type) {case int:fmt.Printf("Twice %v is %v\n", v, v*2)case string:fmt.Printf("%q is %v bytes long\n", v, len(v))default:fmt.Printf("I don't know about type %T!\n", v)}
}func main() {do(21)do("hello")do(true)
}

片段

文件嵌入

Go程序可以使用"embed"包嵌入静态文件,如下所示:

package mainimport ("embed""log""net/http"
)// content holds the static content (2 files) for the web server.
//go:embed a.txt b.txt
var content embed.FSfunc main() {http.Handle("/", http.FileServer(http.FS(content)))log.Fatal(http.ListenAndServe(":8080", nil))
}

完整的Playground示例

HTTP服务器

package mainimport ("fmt""net/http"
)// define a type for the response
type Hello struct{}// let that type implement the ServeHTTP method (defined in interface http.Handler)
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "Hello!")
}func main() {var h Hellohttp.ListenAndServe("localhost:4000", h)
}// Here's the method signature of http.ServeHTTP:
// type Handler interface {
//     ServeHTTP(w http.ResponseWriter, r *http.Request)
// }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/93315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式10、外观模式Facade

解释说明&#xff1a;外观模式&#xff08;Facade Pattern&#xff09;又称为门面模式&#xff0c;属于结构型模式 Faade 为子系统中的一组接口提供了一个统一的高层接口&#xff0c;该接口使得子系统更加容易使用 外观&#xff08;Facade)角色&#xff1a;为多个子系统对外提供…

Sql注入(手工注入思路、绕过、防御)

一、Sql注入思路 1、判断注入点 在GET参数、POST参数、以及HTTP头部等&#xff0c;包括Cookie、Referer、XFF(X-Forwarded-for)、UA等地方尝试插入代码、符号或语句&#xff0c;尝试是否存在数据库参数读取行为&#xff0c;以及能否对其参数产生影响&#xff0c;如产生影响则…

信创办公–基于WPS的EXCEL最佳实践系列 (数据整理复制粘贴)

信创办公–基于WPS的EXCEL最佳实践系列 &#xff08;数据整理复制粘贴&#xff09; 目录 应用背景操作步骤1、数据查找与替换2、复制或粘贴数据3、使用自动填充工具4、将数据拆分到多列5、应用数字格式 应用背景 数据的整理复制粘贴等在日常的工作中经常使用。本章内容主要学习…

设计模式 - 享元模式

目录 一. 前言 二. 实现 一. 前言 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它主要解决的问题是创建大量相似对象时的内存开销问题。该模式通过共享具有相同状态的对象来减少内存使用量。 享元模式的思想是&#xff1a;当需要创建…

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③ 第十九章 驱动程序基石③19.5 定时器19.5.1 内核函数19.5.2 定时器时间单位19.5.3 使用定时器处理按键抖动19.5.4 现场编程、上机19.5.5 深入研究&#xff1a;定时器的内部机制19.5.6 深入研究&#xff1a;找到系统滴答 1…

SpringCloud(一)Eureka、Nacos、Feign、Gateway

文章目录 概述微服务技术对比 Eureka服务远程调用服务提供者和消费者Eureka注册中心搭建注册中心服务注册服务发现Ribbon负载均衡负载均衡策略饥饿加载 NacosNacos与Eureka对比Nacos服务注册Nacos服务分集群存储NacosRule负载均衡服务实例权重设置环境隔离 Nacos配置管理配置热…

ESP32设备驱动-OLED-SSD1306(I2C)显示屏驱动

OLED-SSD1306(I2C)显示屏驱动 1、OLED介绍 OLED显示屏是指有机电激发光二极管(OrganicLight-EmittingDiode,OLED)由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一…

C++面试题准备

文章目录 一、线程1.什么是进程&#xff0c;线程&#xff0c;彼此有什么区别?2.多进程、多线程的优缺点3.什么时候用进程&#xff0c;什么时候用线程4.多进程、多线程同步&#xff08;通讯&#xff09;的方法5.父进程、子进程的关系以及区别6.什么是进程上下文、中断上下文7.一…

短期风速预测|LSTM|ELM|批处理(matlab代码)

目录 1 主要内容 LSTM-长短时记忆 ELM-极限学习机 2 部分代码 3 程序结果 4 程序链接 1 主要内容 该程序是预测类的基础性代码&#xff0c;程序对河北某地区的气象数据进行详细统计&#xff0c;程序最终得到pm2.5的预测结果&#xff0c;通过更改数据很容易得到风速预测结…

WSL2安装历程

WLS2安装 1、系统检查 安装WSL2必须运行 Windows 10 版本 2004 及更高版本&#xff08;内部版本 19041 及更高版本&#xff09;或 Windows 11。 查看 Windows 版本及内部版本号&#xff0c;选择 Win R&#xff0c;然后键入winver。 2、家庭版升级企业版 下载HEU_KMS_Activ…

Django模板加载与响应

前言 Django 的模板系统将 Python 代码与 HTML 代码解耦&#xff0c;动态地生成 HTML 页面。Django 项目可以配置一个或多个模板引擎&#xff0c;但是通常使用 Django 的模板系统时&#xff0c;应该首先考虑其内置的后端 DTL&#xff08;Django Template Language&#xff0c;D…

【Flutter】Flutter Web 开发 如何从 URL 中获取参数值

【Flutter】Flutter Web 开发 如何从 URL 中获取参数值 文章目录 一、前言二、Flutter Web 中的 URL 处理三、如何从 URL 中获取参数四、实际业务中的用法五、完整示例六、总结 一、前言 大家好&#xff01;我是小雨青年&#xff0c;今天我想和大家分享一下在 Flutter Web 开发…

UGUI交互组件Button

一.初识Button对象 从菜单中创建Button对象&#xff0c;Button的文本由子节点Text对象显示&#xff0c;Button对象的组件除了基础组件外&#xff0c;还有Image用来显示Button常规态的图片&#xff0c;还有Button组件用来控制点击过渡效果和点击事件的响应。 二.Button组件的属…

C#,数值计算——Ranq1的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Recommended generator for everyday use.The period is 1.8E19. Calling /// conventions same as Ran, above. /// </summary> public class Ranq1 { …

【2023年11月第四版教材】第17章《干系人管理》(第二部分)

第17章《干系人管理》&#xff08;第二部分&#xff09; 4 过程1-识别干系人4.1 数据收集★★★4.3数据分析4.4 权力利益方格4.5 数据表现&#xff1a;干系人映射分析和表现★★★ 5 过程2-规划干系人参与5.1 数据分析5.2 数据表现★★★5.2.1 干系人参与度评估矩阵★★★ 5.3 …

git_SSL certificate problem: unable to get local issuer certificate解决办法

拉取问题 再拉取代码的时候&#xff0c;报这个错误 这是由于当你通过HTTPS访问Git远程仓库的时候&#xff0c;如果服务器上的SSL证书未经过第三方机构认证&#xff0c;git就会报错。原因是因为未知的没有签署过的证书意味着可能存在很大的风险。解决办法就是通过下面的命令将…

【算法分析与设计】回溯法(上)

目录 一、学习要点1.1 回溯法1.2 问题的解空间1.3 0-1背包问题的解空间1.4 旅行售货员问题的解空间1.5 生成问题状态的基本方法 二、回溯法的基本思想三、回溯算法的适用条件四、递归回溯五、迭代回溯六、子集树与排列树七、装载问题八、批处理作业调度问题 一、学习要点 理解回…

操作系统初探 - 进程的概念

目录 预备知识 冯诺依曼和现代计算机结构 操作系统的理解 进程和PCB的概念 PCB中的信息 查看进程信息的指令 - ps pid 进程状态 预备知识 在学习操作系统之前我们需要先了解一下如下的预备知识。 冯诺依曼和现代计算机结构 美籍匈牙利科学家冯诺依曼最先提出“程序存…

POJ 3109 Inner Vertices 离散化+树状数组

一、题目大意 围棋棋盘&#xff0c;如果某个坐标上下左右的四个方向都存在棋子&#xff0c;那么ans1&#xff0c;根据输入的棋子数量&#xff0c;求出ans的数量。 二、解题思路 题目中有说到如果程序不会结束&#xff0c;那么输出-1&#xff0c;这其实是无源之水&#xff0c…

【爬虫】用wget命令爬虫的简易教程

文章目录 1. 获取登录的请求2. 用postman模拟登录请求3. 用wget模拟登录请求并保存cookie4. 开始爬取网站5. 查看爬取结果6. 网站爬虫简易教程 爬取需要登录的网站的资源 背景&#xff1a;对于一些网站需要使用用户名和密码登录并且使用了https&#xff0c;我们如果不通过凭证将…