Golang笔记(一)简洁的语言风格

概述

Golang继承了很多C语言的风格,寡人使用了十几年C语言,切换到Golang时上手很快,并且随着深入的使用,越来越喜欢这门语言。Golang最直观的感受是简洁(语言细节少)、高效(开发迅速)和高性能(忽略GC时,类比C++的性能)。

package

package是golang最基本的分发单位。每个golang源代码文件开头都要申明其属于哪个package。如果输出的是可执行文件,则必须定义一个'main' package和属于它的一个main()函数。

通过import关键字引用其需要用到的package,这和C语言的include类似。使用其他package的函数,直接用.操作符即可,非常简洁,无需像C语言一样需要通过头文件将需要使用的函数和变量进行声明,也没有头文件包含的顺序问题。下面这个栗子,用os.OpenFile直接调用package "os"里的OpenFile函数。

package main

import (
"log"
"os"
) func main() {
f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}

Golang语言生态比较完善,有大量的库可以使用,只需要将对应的package进行import即可。

goroutine

Golang独特的goroutine机制实现多线程并行处理。使用简单的go func()语句即可启动一个goroutine。一个goroutine并不等同于一个线程,实际上Golang底层封装了线程。一个线程绑定到CPU某核,其上循环运行多个goroutine。goroutine是按照抢占式进行调度的,一个goroutine执行一会(如10ms)就会被切换到下一个。

Golang独特的channel机制实现goroutine之间消息交互。channel类似一个消息管道,管道里承载着一种类型为type的数据,通过make(chan type, size)函数定义,size为channel里缓存个数。通过chan <- value写入value到channel,通过value <- chan读取channel里的数据。当channel里没有数据时,读取操作会一直阻塞。同样当channel里缓存满了(没有及时读取),写入操作也会一直阻塞。所以channel也可以用于goroutine之间的同步。

多返回值

Golang函数可以定义多个返回值。这是对C语言的一大改进,在C语言里要想返回多个参数时,只能开辟指针以函数入参的形式带入。这个痛苦在Golang则完全没有。Golang的多参数返回值也非常易于error的返回和处理,相比高级语言里的繁琐的exceptions体系更加简洁易用。看下面代码,OpenFile函数返回了File指针类型和error类型的两个参数,在上面那个栗子里可以看到如何获取两个参数返回值。

package os
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}

指针

Golang保留了C语言的指针类型。使用指针时,*&的含义和C语言一样。

Golang同时也简化了对指针的使用。在C语言中你需要用->操作符来使用指针指向的结构体的值,而结构体变量则使用.操作符。Golang无论指针还是结构体变量,都使用.,这点让码农多数时候甚至都不用关心到底在使用指针还是结构体变量。另外Golang不支持指针运算。C语言里的指针运算虽然灵活,但用的不好很容易出界。

变量

Golang的变量在声明时自动做了初始化。数值型变量默认赋值0,string或者指针变量默认赋值nil,slice变量默认是个空的slice等等。再也不用担心C语言里变量声明时忘记初始化导致的BUG。

Golang的变量支持隐藏式声明,通过":="的方式将其声明为右边的类型。这个设计可以大幅减少变量显示声明,简化了代码。同时也方便了码农,有时候用":="函数的返回值,都不用太care到底返回的类型是啥。Golang本身并不支持"泛型"变量,但通过:=和Interface可以实现类似"泛型"的特性。

另外,Golang支持"%v"自动匹配变量类型的打印输出方式,如果变量是一个结构体类型,则将结构体内的所有字段全部输出。这在高级语言里可能很常见,但作为C语言切换来的码农,这个特性可以大幅提高调试日志的编码效率。要输出一个结构体里几十个字段,在C语言里一个字段一个字段的码代码是多么痛苦的回忆。

array和slice

Golang的array和C语言的数组是一样的概念,用法也是完全一样。数组定义了之后长度无法改变,同时数组是值类型,每次传递都会拷贝一个副本(当然也可以显示使用数组的指针来传递)。

Golang提供了一种更灵活的“动态数组”:slice和array类似,只是其长度可变,可随时为新的数据扩大数组长度。

slice本质上并不是动态数组,它是一个引用类型。slice的内部实现总是指向了一个array。slice数据结构可以抽象为:

  1. 一个指向array或者array偏移位置的指针;
  2. slice的长度len;
  3. slice分配的存储空间cap;

理解了slice是什么,再通过代码样例来看看如何使用slice:

var a = [10]int {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} //定义数组并初始化
var s []int //slice的声明和array的区别是[]里为空
s = a[:5] //赋值s为a的0~4位置,此时slice指向a[0]并且len=5,cap=10。对数组或者slice的截取访问的格式可以是[:5],或者[3:5],或者[3:],或者[:],分别对应0~4,3~4, 3~len-1,0~len-1
s[0] = -1 //slice的赋值只是指针指向的方式进行引用,因此对s[0]的修改会导致a[0]也被改变。 s1 := make([]int, 5, 10) //通过make创建一个int类型的slice,并且len=5,cap=10。其中5个元素值初始化为0。
fmt.Printf("len: %v, cap: %v", len(s1), cap(s1)) //通过len()和cap()函数返回slice的len和cap
for i, v := range s1 { //通过'range'关键字遍历slice,同样的方法也用于遍历array和map。
fmt.Println(v)
}
s1 := append(s1, 5,6,7) //通过append()函数扩展s1
s2 := append(s1, 8) //此时s1,s2指向的是同一个底层array,只是s1指向0~7,s2指向的是0~8,修改s2会影响s1里的数据。
s3 := append(s1, s2) //将s2 append到s1时等效于将s2里的数据append到s1,由于s1的cap不够存储append后的数据,底层会分配一个新的array用于返回。
n := copy(s3, s1) //通过copy()函数可以将数据从array/slice拷贝到slice,返回的n为实际拷贝大小即s1,s3两个slice的较小的长度。
n := copy(s2, s1) //s1,s2底层指向同一个array,因此copy()会发生元素重叠

map

Golang也提供map类型,即key-value的集合。map的操作和slice一样,通过key来操作。不同的是slice的索引是int类型,map则可以是int后者string等类型,并完全支持了'=='和'!='操作符。

在C++/Java中,map一般都以库的方式提供,比如在C++中是STL的std::map<>,在Java中是Hashmap<>。而Golang使用map不需要引入任何库,并且用起来也更加方便。通过如下代码来熟悉下map:

var m map[string]int    	//声明一个string类型key,int类型value的map。需要注意map只是声明就使用,会抛出panic,必须通过make或者其他方法进行创建后才能使用。
m = make(map[string] int) //通过make创建map,也可以指定初始化存储空间:make(map[string] int, 10)
m["first"] = 1 //直接赋值的方式插入或者修改map元素
fmt.Println(len(m)) //len()函数同样可以用于显示map的长度
v, ok := m["first"] //查找key对应value,如果不存在了ok==false
if ok {
fmt.Println(v)
}
for k, v := range m { //使用range遍历map所有元素,返回每个key和value
fmt.Println(v)
}
delete(m, "first") //通过delete()函数将对应元素删除,元素不存在也没有关系,不会panic

总结

Golang的这些特点让它的代码显得非常简洁,开发效率高,性能媲美C++,当然其GC还是会成为性能的瓶颈。

Golang笔记(一)简洁的语言风格的更多相关文章

  1. golang学习笔记18 用go语言编写移动端sdk和app开发gomobile

    golang学习笔记18 用go语言编写移动端sdk和app开发gomobile gomobile的使用-用go语言编写移动端sdk和app开发https://blog.csdn.net/u01249 ...

  2. 读书笔记之:C语言深度剖析

    读书笔记之:C语言深度剖析 <C 语言深度解剖>这本书是一本“解开程序员面试笔试的秘密”的好书.作者陈正冲老师提出“以含金量勇敢挑战国内外同类书籍”,确实,这本书中的知识点都是一些在面试中 ...

  3. golang笔记1

    golang笔记1 go代码是用包来组织的,每个包有一个或多个go文件组成,这些go文件文件放在一个文件夹中 每个源文件开始都用一个package声明,指明本源文件属于哪个包 pakage声明后紧跟这 ...

  4. Golang笔记(二)面向对象的设计

    Golang笔记(二)面向对象的设计 Golang本质还是面向过程的语言,但它实现了一些OOP的特性,包括抽象.封装.继承和多态. 抽象和封装 Golang和C语言一样以struct为数据结构核心,不 ...

  5. C++_系列自学课程_第_9_课_C语言风格字符串_《C++ Primer 第四版》

    前面说了写关于数组和指针的内容,这次在这里讨论一下字符串,讨论一下C语言风格的字符串. 在C语言里面我们利用字符数组来对字符串进行处理, 在C++里面我们前面说过一种类类型string可以对字符串进行 ...

  6. 《30天自制操作系统》笔记(02)——导入C语言

    <30天自制操作系统>笔记(02)——导入C语言 进度回顾 在上一篇,记录了计算机开机时加载IPL程序(initial program loader,一个nas汇编程序)的情况,包括IPL ...

  7. [编程笔记]第一章 C语言概述

    //C语言学习笔记 第一讲 C语言概述 第二讲 基本编程知识 第三讲 运算符和表达式 第四讲 流程控制 第五讲 函数 第六讲 数组 第七讲 指针 第八讲 变量的作用域和存储方式 第九讲 拓展类型 第十 ...

  8. 《Essential C++》读书笔记 之 基于对象编程风格

    <Essential C++>读书笔记 之 基于对象编程风格 2014-07-13 4.1 如何实现一个class 4.2 什么是Constructors(构造函数)和Destructor ...

  9. C++的string类型和继承C语言风格的字符串的区别与注意事项

    1.尽可能地在C++程序中使用string,不要使用继承而来的C语言风格的字符串,会出现许多安全问题. 2.C语言的字符串风格,是以空字符结束的,在C++的头文件cstring中定义了C语言风格的字符 ...

随机推荐

  1. 从底层了解ASP.NET体系结构

    导读:  前言  关于ASP.NET的底层的工作机制,最近园子里讨论的甚是火热.相信很多人都看过Rick Strahl先生的一篇经典之作:A low-level Look at the ASP.NET ...

  2. JS控制A标记的href跳转

    var a = document.getElementById("aHref"); a.href = '/user'; //取消<a>标签原先的onclick事件,使& ...

  3. PS2018学习笔记(03-18节)

    3-认识主界面 # 主界面包括: 菜单栏.选项栏.工具栏.面板.图像编辑窗口(中间)和状态栏(底部): # 界面设置: 方法1:Ctrl+k:打开界面设置; 方法2:编辑-首选项-界面 # shift ...

  4. Python中dataframe\ array\ list相互转化

    import pandas as pd import numpy as np #创建列表 a1=[1,2,3] #arange函数:指定初始值.终值.步长来创建数组 a2=np.arange(0,1, ...

  5. 取数字(dp优化)

    取数字(dp优化) 给定n个整数\(a_i\),你需要从中选取若干个数,使得它们的和是m的倍数.问有多少种方案.有多个询问,每次询问一个的m对应的答案. \(1\le n\le 200000,1\le ...

  6. Vue知识分享一

    最近想着把之前学的Vue的知识整理一下,方便在公司和同事一起分享.我想要按照下面几个方面去说一下,我对vue的学习理解. 一.什么是VUE vue.js是一个用来开发Web界面的前端库,是很轻量级的工 ...

  7. 剑指offer —— 替换空格

    1.问题:请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 2.思路:可能首先想到的应该就是 ...

  8. Ubuntu安装SHH服务

    1.打开"终端窗口",输入"sudo apt-get update"-->回车-->"输入当前登录用户的管理员密码"--> ...

  9. oracle随笔

    Oracle新建数据库(新用户) 1.首先,创建(新)用户: create user username identified by password; username:新用户名的用户名 passwo ...

  10. N - 嘤嘤嘤 (并查集+枚举)

    Our lovely KK has a difficult Social problem. A big earthquake happened in his area. N(2≤N≤2000)N(2≤ ...