#452 Golang: 格式化输出
Golang 2020-12-06Golang 格式化输出靠 fmt 库。
(f|s)?(scan|print)(f|ln)? 一组合就有 18 个方法了,再加上一个 Errorf。
coding in a complicated world
Golang 格式化输出靠 fmt 库。
(f|s)?(scan|print)(f|ln)? 一组合就有 18 个方法了,再加上一个 Errorf。
new 和 make
$ 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) *Typefunc make(t Type, size ...IntegerType) Typenew 和 make 的区别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 出的指针完全相同。暂时没有想明白这样设计的好处。
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
var 变量const 常量type 类型func 函数go 并发chan 信道select 分支interface 接口map 映射struct 结构体defer 延迟执行goto 跳转return 返回forcontinuebreakrange 用于读取 slice、map、channel 数据ifelseswitchcasedefaultfallthroughpackageimportTypes:
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
truefalseiotanilintint8int16int32int64uintuint8uint16uint32uint64complex64complex128float32float64byte => uint8rune => int32stringanycomparablebooluintptr 指针error 一个内置的 interfaceappenddeleteclose
cap
len
copy
make
new
panic
recover
print
println
real
imagcomplextpl := `[%s] Your verify code is %s.`
s := fmt.Sprintf(tpl, "Markjour", "1234")
println(s)
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] }))
这两个就可以处理复杂的情况,嵌套模板,控制语句都支持。
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)
}
这是大神 zzzeek 2015 年发表的一篇文章,详细介绍了关于 SQLAlchemy 与异步编程的一些事情。解答了我关于如何实现异步编程的一些疑惑。
我曾反复阅读这篇文章好多遍,以求能够更加准确地领会到大佬阐述的意思。我认为每个 Python 的使用者都应该阅读阅读。
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),然后修改其中的一个字段。
| 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。
BOM 是 Byte Order Mark 的缩写,代表一个 Unicode 字符 FEFF。
Windows 系统下的很多软件就用 BOM 字符作为 Magic Number, 用来确认文件的字符编码和字节顺序。
从原理上来讲,我们的计算机其实只认识数字(要不然为什么叫做计算机),确切的说是 0 和 1,我们的文字信息存放在计算机中也是以数字形式存在。
所谓字符编码就是字符和数字之间的对应关系和转换规则。

手持两把锟斤拷,
口中疾呼烫烫烫。
脚踏千朵屯屯屯,
笑看万物锘锘锘。
开发者经常这样调侃编码问题:手持两把锟斤拷,口中疾呼烫烫烫。
程序员都知道字符编码,比如 ASCII,GBK,UTF-8,那肯定能理解这些神奇的 “乱码” 出现的原因,肯定是某些地方没有正确处理编码。
那为什么总是能看见 锟斤拷,烫烫烫呢?其背后隐藏更深的原因是啥?