Golang系列教程1:数据类型

  • 80
  • 2022年5月15日16:14:47
  • 阅读模式
摘要

Golang特点- 原生并发- 轻量简单- 部署方便大写字母开头的常量在包外可见小写字母开头的常量只能在包内访问

【凡蜕博客】Golang系列教程1:数据类型

Golang特点

  • 原生并发
  • 轻量简单
  • 部署方便

常量

// 定义常量
const a = '12'    # 单个
const a, b = 12, '12' # 多个

// 枚举,可以有表达式,但是要用内置函数len(), cap(), unsafe.Sizeof()
const{
      a = "abc"
      b = len(a)
      c = unsafe.Sizeof(a)
}

iota  // 可以认为是枚举的行索引,第一个 iota 等于 0
const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )

大写字母开头的常量在包外可见

小写字母开头的常量只能在包内访问

函数体内声明的常量只能在函数体内生效

常量中只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

变量

声明变量

var a int
var a int = 1
var a, b, c int     //同一类型的多个变量可以声明在同一行
a := 1
a, b, c := 5, 7, "abc"

var (
  a int
  b string
)

a, b = b, a   //交换两个变量的值

当一个变量被声明之后,系统自动赋予它该类型的零值:int 为 0,float 为 0.0,bool 为 false,string 为空字符串"",指针为 nil。记住,所有的内存在 Go 中都是经过初始化的。

变量命名:小驼峰

布尔

result := true

数值

1、整数:

  • int8(-128 -> 127)
  • int16(-32768 -> 32767)
  • int32(-2,147,483,648 -> 2,147,483,647)
  • int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)

整型的零值为 0

2、无符号整数:

  • uint8(0 -> 255)
  • uint16(0 -> 65,535)
  • uint32(0 -> 4,294,967,295)
  • uint64(0 -> 18,446,744,073,709,551,615)

3、浮点型(IEEE-754 标准):

  • float32(+- 1e-45 -> +- 3.4 * 1e38)
  • float64(+- 5 1e-324 -> 107 1e308)(推荐)

float32 精确到小数点后 7 位,float64 精确到小数点后 15 位. 使用 == 或者 != 来比较浮点数时应当非常小心

尽可能地使用 float64,math 包中所有有关数学运算的函数都会要求接收这个类型

浮点型的零值为 0.0。

4、复数

  • complex64 (32 位实数和虚数)
  • complex128 (64 位实数和虚数)

复数使用 re+imI 来表示,其中 re 代表实数部分,im 代表虚数部分,I 代表根号负 1。

eg:var c1 complex64 = 5 + 10i // 输出: 5 + 10i

5、格式化符号

  • %d 十进制表示
  • %b 二进制表示
  • %o 八进制表示
  • %c 相应Unicode码点所表示的字符
  • %U Unicode格式:123,等同于 "U+007B"
  • %x 十六进制表示,字母形式为小写 a-f
  • %X 十六进制表示,字母形式为大写 A-F
  • %q 单引号围绕的字符字面值,由Go语法安全地转义
  • %g 用于格式化浮点型——
  • %f 输出浮点数;
  • %e 输出科学计数表示法
  • %0d 用于规定输出定长的整数
  • %n.mg 用于表示数字 n 并精确到小数点后 m 位,除了使用 g 之外,还可以使用 e 或者 f,例如: %5.2e 来输出 3.4 的结果为 3.40e+00
  • %v 只输出所有的值
  • %+v 先输出字段类型,再输出该字段的值
  • %#v 先输出结构体名字值,再输出结构体(字段类型+字段的值)
  • %T 相应值的类型的Go语法表示
  • %% 百分号,字面上的%,非占位符含义

6、位运算

  • 按位与 &
  • 按位或 |
  • 按位异或 ^
  • 位清除 &^

7、逻辑运算符

==、!=、<、<=、>、>=

8、算数运算符
+、-、* 、 /

/ 对于整数运算而言,结果依旧为整数

取余运算符只能作用于整数

9、随机数

a := rand.Int()

r := rand.Intn(8)

rand.Intn 返回介于 [0, n) 之间的伪随机数。

rand.Float32rand.Float64 返回介于 [0.0, 1.0) 之间的伪随机数,其中包括 0.0 但不包括 1.0

10、运算符优先级

优先级 运算符
7: ^ !
6: * / % << >> & &^
5: + - | ^
4: == != < <= >= >
3: <-
2: &&
1: ||

字符串

字符串是一种值类型,且值不可变,即创建某个文本后你无法再次修改这个文本的内容;更深入地讲,字符串是字节的定长数组。

Go 中的字符串也可能根据需要占用 1 至 4 个字节(示例见第 4.6 节),这与其它语言如 C++、Java 或者 Python 不同(Java 始终使用 2 个字节)。Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。

Go 中使用 strings 包来完成对字符串的主要操作。

拼接字符串:

  • 在少量仅有字符串类型的变量拼接字符串时,并且对性能要求不高的场景,推荐使用操作符 + 的方式; str := "a" + "b" + "c"

  • 在字符串类型切片中的元素拼接字符串时,推荐使用 strings.Join 方式; s := []string{"a", "b", "c"} str := strings.Join(s, ", ")

  • 在少量多种类型变量拼接字符串时,推荐使用 fmt.Sprint 的方式;

    str := fmt.Sprint("a", 1, "b\r\n")
    str1 := fmt.Sprintf("name:%s,age=%d.\r\n", "lucy", 17)
    str2 := fmt.Sprintln("a", 1, "b")

  • 在少量字符串、字符和 Unicode 拼接字符串时,并且对性能有一定要求的场景,推荐使用 buyes.Buffer 的方式;

    var b bytes.Buffer
    b.WriteString("My ")
    b.WriteString("name ")
    b.WriteString("is ")
    b.WriteString("lucy.")
    str := b.String()

  • 在大量字符串、字符和 Unicode 拼接字符串时。并且对性能有一定要求的场景,推荐使用 strings.Builder 的方式。

    var b bytes.Builer
    b.WriteString("My ")
    b.WriteString("name ")
    b.WriteString("is ")
    b.WriteString("lucy.")
    str := b.String()

获取字符串长度

  • len(str)
  • utf8.RuneCountInString(str) 效率会更高一点

获取字符

  • 第 i 个字节:str[i - 1]
  • 最后 1 个字节:str[len(str)-1]
  • 第 1 个字节:str[0]

获取子字符串:

  • str[start:end]:从字符串 str 获取到从索引 start 开始到 end-1 位置的子字符串
  • str[start:] 则表示获取从 start 开始到 len(str)-1 位置的子字符串
  • str[:end] 表示获取从 0 开始到 end-1 的子字符串。

前缀和后缀:

  • strings.HasPrefix(str, "He") bool
  • strings.HasSuffix(str, "ld!") bool

是否包含某字符串:

  • strings.Contains(s, substr string) bool

判断子字符串或字符在父字符串中的索引

  • strings.Index(s, str string) int //第一个字符的索引
  • strings.LastIndex(s, str string) int //str 在字符串 s 中最后出现位置的索引,-1 表示不包含
  • strings.IndexRune(s string, r rune) int //如果 ch 是非 ASCII 编码的字符

字符串替换:

  • strings.Replace(str, old, new, n) string //将字符串 str 中的前 n 个字符串 old 替换为字符串 new,n = -1 则替换所有字符串 old 为字符串 new

修改某个字符:

  • s := "hello" ;c := []byte(s); c[0] = 'c' ;s2 := string(c) ; // s2 == "cello"
  • 必须先将字符串转换成字节数组,然后再通过修改数组中的元素值来达到修改字符串的目的,最后将字节数组转换回字符串格式。

统计字符串出现次数:

  • strings.Count(s, str string) int //计算字符串 str 在字符串 s 中出现的非重叠次数

重复字符串:

  • strings.Repeat(s, count int) string //重复 count 次字符串 s 并返回一个新的字符串

修改大小写:

  • strings.ToLower(s) string //将字符串中的 Unicode 字符全部转换为相应的小写字符:
  • strings.ToUpper(s) string

修剪字符串:

  • strings.TrimSpace(s) //剔除字符串开头和结尾的空白符号
  • strings.Trim(s, "cut") //将开头和结尾的 cut 去除掉
  • strings.TrimLeft(s, "cut") //仅开头
  • strings.TrimRight(s, "cut") // 仅结尾

分割字符串:

  • strings.Fields(s) //用空白作为分隔符将字符串分割为若干块,并返回一个 slice,习惯使用 for-range 循环来对其进行处理
  • strings.Split(s, sep) //自定义分割符号对字符串分割,返回 slice ,习惯使用 for-range 循环来对其进行处理

拼接 slice 到字符串:

  • strings.Join(sl []string, sep string) string //将元素类型为 string 的 slice 使用分割符号来拼接组成一个字符串

类型转换:

  • 任何类型 T 转换为字符串总是成功的

  • strconv.Itoa(i int) string //返回数字 i 所表示的字符串类型的十进制数。

  • strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string

    将 64 位浮点型的数字转换为字符串,其中 fmt 表示格式(其值可以是 'b'、'e'、'f' 或 'g'),prec 表示精度,bitSize 则使用 32 表示 float32,用 64 表示 float64。

  • val, err = strconv.Atoi(s string) (i int, err error) //将字符串转换为 int 型

  • val, err = strconv.ParseFloat(s string, bitSize int) (f float64, err error) //将字符串转换为 float64 型。

时间日期

time包

carbon库:https://segmentfault.com/a/1190000021754301

当前时间

  1. time.Now()
  2. carbon.Now() //.ToDateTimeString()

代码耗时

  1. time.Now()
    end := time.Now()
    fmt.Println(end.Sub(start))

日期格式化

  1. now := time.Now()

    now.Format("2006/01/02 15:04")

其他文档http://docs.studygolang.com/pkg/strings/

指针

&:获取变量的内存地址,叫做指针

*:修改指针对应的变量的值

package main
import "fmt"
func main() {
    s := "good bye"
    var p *string = &s
    *p = "ciao"
    fmt.Printf("p: %p\n", p) // 0x2540820
    fmt.Printf("*p: %s\n", *p) // ciao
    fmt.Printf("s: %s\n", s) // ciao
}

指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。

不能得到一个文字或常量的地址.

传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return 返回。如下的例子,reply 是一个指向 int 变量的指针,通过这个指针,我们在函数内修改了这个 int 变量的数值。

package main

import (
    "fmt"
)

// this function changes reply:
func Multiply(a, b int, reply *int) {
    *reply = a * b
}

func main() {
    n := 0
    reply := &n
    Multiply(10, 5, reply)
    fmt.Println("Multiply:", *reply) // Multiply: 50
}

什么时候用指针?

什么是receiver?

func (t T) method_name(t T){}
1

这里面的T就是receiver

如果receiver是map、func或者chan,不要使用指针
如果receiver是slice并且该函数并不会修改此slice,不要使用指针
如果该函数会修改receiver,此时一定要用指针
如果receiver是struct并且包含互斥类型sync.Mutex,或者是类似的同步变量,receiver必须是指针,这样可以避免对象拷贝
如果receiver是较大的struct或者array,使用指针则更加高效。多大才算大?假设struct内所有成员都要作为函数变量传进去,如果觉得这时数据太多,就是struct太大
如果receiver是struct,array或者slice,并且其中某个element指向了某个可变量,则这个时候receiver选指针会使代码的意图更加明显
如果receiver使较小的struct或者array,并且其变量都是些不变量、常量,例如time.Time,value receiver更加适合,因为value receiver可以减少需要回收的垃圾量。
最后,如果不确定用哪个,使用指针类的receiver

类型转换

//string到int 
int,err:=strconv.Atoi(string) 

//string到int64 
int64, err := strconv.ParseInt(string, 10, 64) 

//int到string 
string:=strconv.Itoa(int) 

//int64到string 
string:=strconv.FormatInt(int64,10)

//string到float32(float64)
float,err := strconv.ParseFloat(string,32/64)

//float到string
string := strconv.FormatFloat(float32, 'E', -1, 32)
string := strconv.FormatFloat(float64, 'E', -1, 64)
// 以下为参数含义
// 'b' (-ddddp±ddd,二进制指数)
// 'e' (-d.dddde±dd,十进制指数)
// 'E' (-d.ddddE±dd,十进制指数)
// 'f' (-ddd.dddd,没有指数)
// 'g' ('e':大指数,'f':其它情况)
// 'G' ('E':大指数,'f':其它情况)
本文来自凡蜕博客(https://blog.ysboke.cn), 转载请带上地址.。
匿名

发表评论

匿名网友