Golang
2020-12-08
byte
实际上是 uint8
的别名,[]byte
也就是 uint8
切片。
常见操作
package main
import (
"bytes"
"encoding/hex"
"fmt"
"strconv"
)
func main() {
// 1. 转换
str1 := "HELLO WORLD"
bytes0 := []byte(str1) // string to bytes
str2 := string(bytes0) // bytes to string
fmt.Printf("%#v\n", bytes0)
// []byte{0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44}
fmt.Println(str1, bytes0, str2)
// HELLO WORLD [72 69 76 76 79 32 87 79 82 76 68] HELLO WORLD
// 2. 连接
bytes1 := []byte("HELLO ")
bytes2 := []byte("WORLD")
bytes3 := append(bytes1, bytes2...)
fmt.Println(bytes3)
// [72 69 76 76 79 32 87 79 82 76 68]
// 3. 拷贝
bytes4 := make([]byte, len(bytes3))
copy(bytes4, bytes3)
fmt.Println(bytes4)
// [72 69 76 76 79 32 87 79 82 76 68]
// 4. 长度和容量
fmt.Println(len(bytes4), cap(bytes4)) // 11 11
// 5. 截取
bytes5 := bytes4[7:10]
fmt.Println(bytes5) // [79 82 76]
// 6. 比较
bytes6 := []byte("HELLO WORLD")
fmt.Println(bytes.Equal(bytes4, bytes6)) // true
// 7. 遍历
for i := 0; i < len(bytes6); i++ {
fmt.Printf("%d ", bytes6[i])
}
fmt.Println()
// 72 69 76 76 79 32 87 79 82 76 68
// 8. 转化为数字
bytes7 := []byte("12345")
num, _ := strconv.Atoi(string(bytes7))
fmt.Println(num) // 12345
// 9. 转化为16进制字符串
bytes8 := []byte("HELLO WORLD")
hexStr := hex.EncodeToString(bytes8)
fmt.Println(hexStr) // 48454c4c4f20574f524c44
}
输出
package main
import (
"bytes"
"fmt"
"io"
"os"
)
func main() {
buf := new(bytes.Buffer) // *bytes.Buffer
// func (b *Buffer) WriteString(s string) (n int, err error)
buf.WriteString("HELLO ")
buf.WriteString("WORLD")
fmt.Println(string(buf.Bytes()))
fmt.Println(buf.String()) // 相同
// ========================================
w := os.Stdout // *os.File
// func (f *File) Write(b []byte) (n int, err error)
// func (f *File) WriteString(s string) (n int, err error)
w.WriteString("HELLO ")
n, err := io.WriteString(w, "WORLD\n")
if err != nil {
panic(err)
}
fmt.Printf("n: %d\n", n)
}
利用 reflect 实现 bytes / string 转换
参考:https://www.sobyte.net/post/2022-01/go-string-bytes/
func String2Bytes(s string) []byte {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: sh.Data,
Len: sh.Len,
Cap: sh.Len,
}
return *(*[]byte)(unsafe.Pointer(&bh))
}
func Bytes2String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
Golang
2020-12-08
package main
func main() {
a := "hello 世界"
fmt.Printf("%#v (%d)\n", a, len(a))
// "hello 世界" (12)
// 按 rune ForRange 循环
for k, v := range a {
fmt.Printf("%#4v. %#6v (%T)\n", k, v, v)
}
// 按 byte 索引取值
fmt.Printf("a[0]: %#6v (%T)\n", a[0], a[0])
fmt.Printf("a[6]: %#6v (%T)\n", a[6], a[6])
// 0. 104 (int32)
// 1. 101 (int32)
// 2. 108 (int32)
// 3. 108 (int32)
// 4. 111 (int32)
// 5. 32 (int32)
// 6. 19990 (int32)
// 9. 30028 (int32)
// a[0]: 0x68 (uint8)
// a[6]: 0xe4 (uint8)
b := []byte(a)
fmt.Printf("%#v\n", b)
// []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c}
c := []rune(a)
fmt.Printf("%#v\n", c)
// []int32{104, 101, 108, 108, 111, 32, 19990, 30028}
}
len(s)
strings.Join(s1, s2) string
连接字符串
strings.ContainsRune(s, rune) bool
strings.Contains(s, substr) bool
子串包含判断
注意:任何字符串都包含空字符串
strings.ContainsAny(s, chars string) bool
字符包含判断
strings.Index(s, substr) int
定位(Rabin-Karp 算法)
strings.Count(s, substr) int
字符计算(Rabin-Karp 算法)
注意:任何字符串包含 n + 1 个空字符串
strings.HasPrefix(s, substr) bool
startswith
strings.HasSuffix(s, substr) bool
endswith
strings.Compare(s1, s2)
大于 1 / 小于 -1 / 等于 0
strings.Repeat(s, num) string
替换子串
strings.Replace(s, substr, replacement, num) string
strings.EqualFold(s1, s2) bool
忽略大小写等于判断
strings.Fields(s)
用空白字符(空格、换行、tab)将字符串切割成字串
strings.Split(s, sep string) []string
切割字符串
strings.SplitAfter(s, sep string) []string
切割字符串(包含分隔符)
strings.SplitAfterN(s, sep string, n int) []string
strings.SplitN(s, sep string, n int) []string
参考 Golang strings
包。
字符串连接:
+
, +=
fmt.Sprintf
strings.Join
bytes.Buffer
var b bytes.Buffer
b.WriteString("hello")
b.WriteString(" world")
fmt.Println(b.String())
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString(" world")
fmt.Println(sb.String())
Golang 正则表达式
2020-12-06
Compile 系列
func Compile(expr string) (*Regexp, error)
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func MustCompilePOSIX(str string) *Regexp
函数名称中的 Must 表示:如果正则错误,直接 panic
Match 系列
func (re *Regexp) Match(b []byte) bool
func (re *Regexp) MatchReader(r io.RuneReader) bool
func (re *Regexp) MatchString(s string) bool
Find 系列
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int
func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string
func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int
func (re *Regexp) FindString(s string) string
func (re *Regexp) FindStringIndex(s string) (loc []int)
func (re *Regexp) FindStringSubmatch(s string) []string
func (re *Regexp) FindStringSubmatchIndex(s string) []int
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int
其实好记,Find(All)?(String)?(Submatch)?(Index)?
一组合就有 16 种了,再加上两个 FindReader
方法。
Replace 系列
func (re *Regexp) ReplaceAll(src, repl []byte) []byte
func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte
func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte
func (re *Regexp) ReplaceAllLiteralString(src, repl string) string
func (re *Regexp) ReplaceAllString(src, repl string) string
func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string
其他
func (re *Regexp) Copy() *Regexp // DEPRECATED
func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte
func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte
func (re *Regexp) LiteralPrefix() (prefix string, complete bool)
func (re *Regexp) Longest()
func (re *Regexp) NumSubexp() int
func (re *Regexp) Split(s string, n int) []string
func (re *Regexp) String() string
func (re *Regexp) SubexpIndex(name string) int
func (re *Regexp) SubexpNames() []string
四个封装方法
func Match(pattern string, b []byte) (matched bool, err error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)
func MatchString(pattern string, s string) (matched bool, err error)
func QuoteMeta(s string) string
示例
func main() {
text := "Hello, 2021! The year 2020 was great, but 2021 will be even better."
pattern := `\b\d{4}\b` // 匹配四个数字的单词
regex, err := regexp.Compile(pattern)
if err != nil {
fmt.Println("Error compiling regex:", err)
return
}
matches := regex.FindAllString(text, -1)
for _, match := range matches {
fmt.Println(match)
}
}
Output:
2021
2020
2021
Golang
2020-12-06
Golang 格式化输出靠 fmt
库。
(f|s)?(scan|print)(f|ln)?
一组合就有 18 个方法了,再加上一个 Errorf
。
Golang
2020-12-05
$ go doc builtin.new
package builtin // import "builtin"
func new(Type) *Type
The new built-in function allocates memory. The first argument is a type,
not a value, and the value returned is a pointer to a newly allocated zero
value of that type.
$ go doc builtin.make
package builtin // import "builtin"
func make(t Type, size ...IntegerType) Type
The make built-in function allocates and initializes an object of type
slice, map, or chan (only). Like new, the first argument is a type, not a
value. Unlike new, make's return type is the same as the type of its
argument, not a pointer to it. The specification of the result depends on
the type:
Slice: The size specifies the length. The capacity of the slice is
equal to its length. A second integer argument may be provided to
specify a different capacity; it must be no smaller than the
length. For example, make([]int, 0, 10) allocates an underlying array
of size 10 and returns a slice of length 0 and capacity 10 that is
backed by this underlying array.
Map: An empty map is allocated with enough space to hold the
specified number of elements. The size may be omitted, in which case
a small starting size is allocated.
Channel: The channel's buffer is initialized with the specified
buffer capacity. If zero, or the size is omitted, the channel is
unbuffered.
func new(Type) *Type
func make(t Type, size ...IntegerType) Type
new
和 make
的区别
- new 没有类型限制,make 只能用来分配和初始化 slice,map,chan。
- new 返回指针,make 返回引用(引用类型的值)。
- new 会将分配的空间置零(对应类型的零值),make 则可以类型初始化,比如 slice 的长度和容量。
package main
import "fmt"
type User struct {
Name string
}
type Addr struct{}
func main() {
user1 := new(User)
user2 := new(User)
fmt.Printf("%#v (%p) %d\n", user1, user1, &user1)
fmt.Printf("%#v (%p) %d\n", user2, user2, &user2)
fmt.Printf("user1 == user2 : %#v\n", user1 == user2)
addr1 := new(Addr)
addr2 := new(Addr)
fmt.Printf("%#v (%p) %d\n", addr1, addr1, &addr1)
fmt.Printf("%#v (%p) %d\n", addr2, addr2, &addr2)
fmt.Printf("addr1 == addr2 : %#v\n", addr1 == addr2)
}
&main.User{Name:""} (0xc00006a250) 824633745448
&main.User{Name:""} (0xc00006a260) 824633745456
user1 == user2 : false
&main.Addr{} (0xf61438) 824633745472
&main.Addr{} (0xf61438) 824633745480
addr1 == addr2 : true
注意上面这一点,空 struct 多次 new 出的指针完全相同。暂时没有想明白这样设计的好处。
Golang
2020-12-05
25 个关键字
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
声明 (4)
var
变量
const
常量
type
类型
func
函数
并发相关 (3)
go
并发
chan
信道
select
分支
类型 (3)
interface
接口
map
映射
struct
结构体
流程控制 (3 + 4 + 6)
defer
延迟执行
goto
跳转
return
返回
循环 (4)
for
continue
break
range
用于读取 slice、map、channel 数据
分支 (6)
if
else
switch
case
default
fallthrough
包 (2)
package
import
39 个预定义标识符
Types:
any bool byte comparable
complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
Constants:
true false iota
Zero value:
nil
Functions:
append cap close complex copy delete imag len
make new panic print println real recover
值 (4)
true
false
iota
nil
类型 (20 + 2)
int (10)
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
complex (2)
complex64
complex128
float (2)
float32
float64
字符与字符串 (3)
byte
=> uint8
rune
=> int32
string
泛型相关 (2) Go1.18+
any
comparable
其他 (3)
bool
uintptr
指针
error
一个内置的 interface
Builtin 函数 (15)
append
delete
-
close
-
cap
-
len
-
copy
-
make
-
new
-
panic
-
recover
-
print
-
println
-
real
imag
complex
Golang
2020-12-01
fmt.Sprintf 字符串格式化
tpl := `[%s] Your verify code is %s.`
s := fmt.Sprintf(tpl, "Markjour", "1234")
println(s)
os.Expand 变量替换
tpl := `[${sign}] Your verify code is ${code}.`
params := map[string]string{"sign": "Markjour", "code": "1234"}
println(os.Expand(tpl, func(k string) string { return params[k] }))
text/template 和 html/template
这两个就可以处理复杂的情况,嵌套模板,控制语句都支持。
package main
import (
"os"
"text/template"
)
func main() {
tpl := `[{{.sign}}] Your verify code is {{.code}}.`
t := template.New("just-a-name")
t, _ = t.Parse(tpl)
params := map[string]string{"sign": "Markjour", "code": "1234"}
t.Execute(os.Stdout, params)
}
附:strings.Map
/ bytes.Map
提供单个字符的替换
func Map(mapping func(rune) rune, s string) string
package main
import (
"fmt"
"strings"
)
const A = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \n"
const B = "N'|&4:@ j{BI+Y!H/Q_iR\\FM}$moLe?#X\"WCE3S,8(r1f%T.;6DbaG]y`q~ltJxu-k2gA\nvhnd=)*s7Z5p^OK[V0z>9<UcwP"
func main() {
encrypt := func(r rune) rune {
if !strings.ContainsRune(A, r) {
return 0
}
return rune(B[strings.IndexRune(A, r)])
}
decrypt := func(r rune) rune {
if !strings.ContainsRune(B, r) {
return 0
}
return rune(A[strings.IndexRune(B, r)])
}
raw := "Life was like a box of chocolate, you never know what you're gonna get."
fmt.Println(raw)
encrypted := strings.Map(encrypt, raw)
fmt.Println(encrypted)
// 3j:4wFN_wIjB4wNw'!Mw!:w| !|!INi4dw}!RwY4\4QwBY!FwF Niw}!RAQ4w@!YYNw@4i)
decrypted := strings.Map(decrypt, encrypted)
fmt.Println(decrypted)
}
参考资料与拓展阅读
Python SQLAlchemy asyncio
2020-11-22
这是大神 zzzeek 2015 年发表的一篇文章,详细介绍了关于 SQLAlchemy 与异步编程的一些事情。解答了我关于如何实现异步编程的一些疑惑。
我曾反复阅读这篇文章好多遍,以求能够更加准确地领会到大佬阐述的意思。我认为每个 Python 的使用者都应该阅读阅读。
Golang
2020-11-20
package main
import (
"fmt"
)
type Person struct {
FirstName string
LastName string
}
func main() {
// 准备 =========================
people := make(map[int]Person)
person := Person{
FirstName: "John",
LastName: "Doe",
}
people[1] = person
// 报错:cannot assign to struct field people[1].FirstName in map
// people[1].FirstName = "Jim"
// 方式 1
p := people[1]
p.FirstName = "Alice"
people[1] = p
fmt.Println(people)
// map[1:{Alice Doe}]
fmt.Println(people[1])
// {Alice Doe}
// if p, ok := people[1]; ok {
// p.Field = 5
// people[1] = p
// }
// 方式 2
people2 := make(map[int]*Person)
people2[1] = &person
people2[1].FirstName = "Adam"
fmt.Println(people2)
// map[1:0xc000060020]
fmt.Println(people2[1])
// &{Adam Doe}
}
总之,不能直接通过 key 找到 value(struct),然后修改其中的一个字段。
Java
2020-11-11
谷歌 Java 趋势
Oracle Java SE Support Roadmap
Release |
GA Date |
Premier Support Until |
Extended Support Until |
7 (LTS) |
July 2011 |
July 2019 |
July 2022 |
8 (LTS) |
March 2014 |
March 2022 |
December 2030 |
9 |
September 2017 |
March 2018 |
- |
10 |
March 2018 |
September 2018 |
- |
11 (LTS) |
September 2018 |
September 2023 |
September 2026 |
12 |
March 2019 |
September 2019 |
- |
13 |
September 2019 |
March 2020 |
- |
14 |
March 2020 |
September 2020 |
- |
15 |
September 2020 |
March 2021 |
- |
16 |
March 2021 |
September 2021 |
- |
17 (LTS) |
September 2021 |
September 2026 |
September 2029 |
18 |
March 2022 |
September 2022 |
- |
19 |
September 2022 |
March 2023 |
- |
20 |
March 2023 |
September 2023 |
- |
21 (LTS) |
September 2023 |
September 2028 |
September 2031 |
PS:Java 9 开始引入了新的模块机制,标准库结构。
PS: 2021 年 Java 17 发布时,Oracle 宣布以后每两年一个 LTS 版本,也就是说下一个 LTS 版本是 21 而非 23。
参考资料与拓展阅读