-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Golang的一些笔记 #84
Comments
相关书籍
|
无缓冲读package main
import "fmt"
func main() {
// create unbuffered channel of int values with capacity of 1
ch := make(chan int)
select {
case ch <- 3:
// uncomment the following line to get this program work
// default:
}
fmt.Printf("ok\n")
}
|
一些工具链
|
包管理,经常看到go.mod文件中,有一些indirect的包,是怎么被依赖进来的,可以用命令 # bingoo @ 192 in ~/GitHub/loglineparser on git:master x [12:40:02]
$ go mod why gopkg.in/yaml.v2
# gopkg.in/yaml.v2
github.com/bingoohuang/loglineparser
github.com/araddon/dateparse
github.com/araddon/dateparse.test
github.com/simplereach/timeutils
gopkg.in/mgo.v2/bson
gopkg.in/mgo.v2/bson.test
gopkg.in/yaml.v2 As of the final 1.11 release, the go module cache (used for storing downloaded modules and source code), is in the $GOPATH/pkg/mod location (see the docs here). For clarification, the go build cache (used for storing recent compilation results) is in a different location. This article, indicated that it's in the $GOPATH/src/mod, but in the timespan of the recent ~40 days, the golang team must have changed that target location. This message thread has some discussion on why the downloaded items ended up in $GOPATH/pkg. You can also use the go mod download -json command to see the downloaded modules/source metadata and their location on your local disk. Example output below: $ go mod download -json {
"Path": "github.com/aws/aws-lambda-go",
"Version": "v1.2.0",
"Info": "/go/pkg/mod/cache/download/github.com/aws/aws-lambda-go/@v/v1.2.0.info",
"GoMod": "/go/pkg/mod/cache/download/github.com/aws/aws-lambda-go/@v/v1.2.0.mod",
"Zip": "/go/pkg/mod/cache/download/github.com/aws/aws-lambda-go/@v/v1.2.0.zip",
"Dir": "/go/pkg/mod/github.com/aws/[email protected]",
"Sum": "h1:2f0pbAKMNNhvOkjI9BCrwoeIiduSTlYpD0iKEN1neuQ=",
"GoModSum": "h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A="
}
{
"Path": "github.com/aws/aws-sdk-go",
"Version": "v1.14.5",
"Info": "/go/pkg/mod/cache/download/github.com/aws/aws-sdk-go/@v/v1.14.5.info",
"GoMod": "/go/pkg/mod/cache/download/github.com/aws/aws-sdk-go/@v/v1.14.5.mod",
"Zip": "/go/pkg/mod/cache/download/github.com/aws/aws-sdk-go/@v/v1.14.5.zip",
"Dir": "/go/pkg/mod/github.com/aws/[email protected]",
"Sum": "h1:+l1m6QH6LypE2kL0p/G0Oh7ceCv+IVQ1h5UEBt2xjjU=",
"GoModSum": "h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k="
} |
JSONJSON数据解析,直接给字段赋予json字符串,避免转义package main
import (
"encoding/json"
"fmt"
)
func main() {
s := `[` + `{"name":"bingoo"},{"name":"dingoo"}` + `]`
var arr []interface{}
if err := json.Unmarshal([]byte(s), &arr); err != nil {
panic(err)
}
m := map[string]interface{}{"key1": arr, "key2": s, "key3": json.RawMessage([]byte(s))}
jso, err := json.Marshal(m)
if err != nil {
panic(err)
}
// {"key1":[{"name":"bingoo"},{"name":"dingoo"}],"key2":"[{\"name\":\"bingoo\"},{\"name\":\"dingoo\"}]","key3":[{"name":"bingoo"},{"name":"dingoo"}]}
fmt.Println(string(jso))
} JSON解析库
Alternate implementationsPopular replacements for standard library packages:
|
强制确保类型实现某个接口Go语言中,类型实现某个接口 ,只要实现了该接口中所有定义的方法即可,没有像Java中的implements关键字,是一种契约式精神的体现,或者说鸭子类型。那有没有强制某个类型必须某个接口的写法呢,刚刚在翻阅jons.RawMessage中看到了以下两行代码,刚开始感觉迷惑,仔细思考后,便了解了其意图: var _ Marshaler = (*RawMessage)(nil)
var _ Unmarshaler = (*RawMessage)(nil) 带上下文的代码如下: // RawMessage is a raw encoded JSON value.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte
// MarshalJSON returns m as the JSON encoding of m.
func (m RawMessage) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
return m, nil
}
// UnmarshalJSON sets *m to a copy of data.
func (m *RawMessage) UnmarshalJSON(data []byte) error {
if m == nil {
return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
}
*m = append((*m)[0:0], data...)
return nil
}
var _ Marshaler = (*RawMessage)(nil)
var _ Unmarshaler = (*RawMessage)(nil) |
在for循环里不要使用select + time.After的组合,有坑本来想给朋友宣称一下,西游可能有Bug,我都已经被挤下线了,但是还能继续谷歌(假百度),然后随便输入了一个golang oom作为搜索条件: 结果就把这个搜索结果页面扔到一边,去干其他事情去了。 等回过头来,打算关闭这个标签页的时候,发现结果第一条,还是有点兴趣的,就点进去看了,最后有这么一句话:
然后,想到自己也经常这么用(for select time.After),很可能踩坑。然后去继续探索了一下,为什么可能会有坑 ,然后将代码中的for select time.After全部重构成 time.Timer + for来预防坑。 Don't use time.Tick to prevent leaks 就是因为在循环中,不停的创建新的计时器,而每个计时器都会开启内部协程。再看看计时器函数的官方注释: // Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only. While Tick is useful for clients that have no need to shut down
// the Ticker, be aware that without a way to shut it down the underlying
// Ticker cannot be recovered by the garbage collector; it "leaks".
// Unlike NewTicker, Tick will return nil if d <= 0.
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
} |
一些代码检查工具
|
检查依赖是否有升级
example output
|
|
Go linux安装
|
首先是执行 ➜ kerb git:(master) ✗ go get golang.org/dl/gotip
go: finding golang.org/dl/gotip latest
go: finding golang.org/dl latest
go: downloading golang.org/dl v0.0.0-20190507014322-219d744c5398
go: extracting golang.org/dl v0.0.0-20190507014322-219d744c5398
➜ kerb git:(master) ✗ gotip download
Cloning into '/Users/bingoobjca/sdk/gotip'...
remote: Counting objects: 9475, done
remote: Finding sources: 100% (9475/9475)
remote: Total 9475 (delta 1010), reused 5862 (delta 1010)
package main
Receiving objects: 100% (9475/9475), 22.11 MiB | 363.00 KiB/s, done.
Resolving deltas: 100% (1010/1010), done.
Checking out files: 100% (8598/8598), done.
HEAD is now at f2a4c13 errors: clarify doc for As
Building Go cmd/dist using /usr/local/go.
Building Go toolchain1 using /usr/local/go.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for darwin/amd64.
---
Installed Go for darwin/amd64 in /Users/bingoobjca/sdk/gotip
Installed commands in /Users/bingoobjca/sdk/gotip/bin
Success. You may now run 'gotip'!
➜ kerb git:(master) ✗ gotip version
go version devel +f2a4c13 Tue Jun 11 21:50:05 2019 +0000 darwin/amd64 |
GOPROXY
GOPROXY=direct,https://127.0.0.1:12333,https://goproxy.cn,https://goproxy.io,https://mirrors.aliyun.com/goproxy,https://athens.azurefd.net
go env -w GOSUMDB="off" |
|
今天我探索了一下golang的两个方面:
然后我发现了函数选项(Functional Options)模式, GIST上有一个最小的例子。 函数选项模式是由Rob Pike提出,并由Dave Cheney等推广开,它优雅地解决了go语言中默认参数问题。 下面总结一下,函数选项模式有哪些优点:
推而广之:类似结构体中变量的赋值都可以效仿之。
|
创建的对象,里面已经启动了一个后台的死循环的go协程,当对象不再被使用时,因为背后的go协程还一直在跑,导致对象不能被gc回收,咋办?,参见go-cache的实现 func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
items := make(map[string]Item)
return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
}
func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
c := newCache(de, m)
// This trick ensures that the janitor goroutine (which--granted it
// was enabled--is running DeleteExpired on c forever) does not keep
// the returned C object from being garbage collected. When it is
// garbage collected, the finalizer stops the janitor goroutine, after
// which c can be collected.
C := &Cache{c}
if ci > 0 {
runJanitor(c, ci)
runtime.SetFinalizer(C, stopJanitor)
}
return C
}
func runJanitor(c *cache, ci time.Duration) {
j := &janitor{
Interval: ci,
stop: make(chan bool),
}
c.janitor = j
go j.Run(c)
} |
以库为驱动开发的Golang工程结构,摘自Library driven development
稍微复杂一点的结构,摘自Go project structure to produce library and cli with the same name in single repository
|
Passing callbacks and pointers to CgoThis post discusses an end-to-end example that covers:
The full source code for this example is available on Github. |
宽进严出原则:
在golang上的应用:
选哪个?
根据 |
看goroutine的数量
参考: |
测试相关TestMain在写测试时,有时需要在测试之前或之后进行额外的设置(setup)或拆卸(teardown);有时,测试还需要控制在主线程上运行的代码。为了支持这些需求,testing 提供了 TestMain 函数: func TestMain(m *testing.M) package mytestmain
import (
"flag"
"fmt"
"os"
"testing"
)
var db struct {
Dns string
}
func TestMain(m *testing.M) {
db.Dns = os.Getenv("DATABASE_DNS")
if db.Dns == "" {
db.Dns = "root:123456@tcp(localhost:3306)/?charset=utf8&parseTime=True&loc=Local"
}
flag.Parse()
exitCode := m.Run()
db.Dns = ""
// 退出
os.Exit(exitCode)
}
func TestDatabase(t *testing.T) {
fmt.Println(db.Dns)
} 参数化测试func TestAdd(t *testing.T) {
tests := []struct{
name string
first int64
second int64
expected int64
} {
{
name: "HappyPath":
first: 2,
second: 3,
expected: 5,
},
{
name: "NegativeNumber":
first: -1,
second: -1,
expected: -2,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, Add(test.first, test.second))
})
}
} 测试集import (
"testing"
"github.com/stretchr/testify/suite"
)
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
}
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
}
func (suite *ExampleTestSuite) TestExample() {
suite.Equal(suite.VariableThatShouldStartAtFive, 5)
}
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
} BDDvar _ = Describe("Book", func() {
var (
book Book
err error
)
BeforeEach(func() {
book, err = NewBookFromJSON(`{
"title":"Les Miserables",
"author":"Victor Hugo",
"pages":1488
}`)
})
Describe("loading from JSON", func() {
Context("when the JSON fails to parse", func() {
BeforeEach(func() {
book, err = NewBookFromJSON(`{
"title":"Les Miserables",
"author":"Victor Hugo",
"pages":1488oops
}`)
})
It("should return the zero-value for the book", func() {
Expect(book).To(BeZero())
})
It("should error", func() {
Expect(err).To(HaveOccurred())
})
})
})
}) Mock
|
go module upgrades dependencies:
|
GO语言的历史,非常好的演讲,值得一看。 编程语言发展的四波浪潮:
Go恢复了早期语言的简单性和灵活性,增加了现代语言的安全性和开发友好性。Go以一种非常真实的方式复兴了许多伟大的想法,这些想法终于准备就绪。
Go的设计哲学
|
Golang枚举生成工具
|
有一种未经证实的说法:
如果C++编译很快,那么Robert Griesemer、Rob Pike和Ken Thompson这三位大佬也没有闲暇时间一起喝着咖啡并决定是时候设计一门新语言了。的确,Go语言诞生后,其简洁的语法、极速地构建、新颖的并发结构、体验优良的工具链以及完成度不低的标准库吸引了很多C/C++程序员转型成为Gopher并开始重度使用Go
|
Different Thread ModelsThere are three different threading models we can see Mx1, 1x1, MxN Go language implemented MxN with three basic primitive entities
FROM Different Threading Models — Why I Feel Go Threading Is Better |
应该有很多人受不了err的反复判断,封装各种err处理,达到简化的目的,其中一种实现ErrorFlow Declarative error handling for Go. func GzipFile(dstFilename string, srcFilename string) (err error) {
// defer IfError()... creates and configures
// ErrorFlow error handler for this function.
// When any of Check* functions encounters non-nil error
// it immediately sends error to this handler
// unwinding all stacked defers.
errWrapper := errf.WrapperFmtErrorw("error compressing file")
defer errf.IfError().ReturnFirst().LogIfSuppressed().Apply(errWrapper).ThenAssignTo(&err)
errf.CheckCondition(len(dstFilename) == 0, "dst file should be specified")
errf.CheckCondition(len(srcFilename) == 0, "src file should be specified")
reader := errf.Io.CheckReadCloser(os.Open(srcFilename))
defer errf.With(errWrapper).Log(reader.Close())
writer := errf.Io.CheckWriteCloser(os.Create(dstFilename))
defer errf.Handle().OnAnyErrOrPanic(func() { os.Remove(dstFilename) })
defer errf.CheckErr(writer.Close())
gzipWriter := gzip.NewWriter(writer)
defer errf.CheckErr(gzipWriter.Close())
return errf.CheckDiscard(io.Copy(gzipWriter, reader))
} |
vendor 打包编译开发机上 $ cd app
$ go mod download -v
$ go mod vendor
$ cd ..
$ tar --exclude .git --exclude .idea -czf app.tar.gz app 编译机上 $ tar zxf app.tar.gz
$ cd app
$ go build -mod vendor -o app -ldflags=' -w -s ' |
package main
import (
_ "expvar"
"net/http"
)
func main() {
http.ListenAndServe(":8100", nil)
}
|
Serve embedded filesystem from root path of URL package main
import (
"embed"
"io/fs"
"log"
"net/http"
)
//go:embed static
var embeddedFS embed.FS
func main() {
serverRoot, err := fs.Sub(embeddedFS, "static")
if err != nil {
log.Fatal(err)
}
http.Handle("/", http.FileServer(http.FS(serverRoot)))
log.Fatal(http.ListenAndServe(":8080", nil))
} |
go可执行文件分析工具redressThe redress software is a tool for analyzing stripped Go binaries compiled with the Go compiler. It extracts data from the binary and uses it to reconstruct symbols and performs analysis. It essentially tries to "re-dress" a "stripped" binary. 🕙[2021-05-05 22:16:16.837] ❯ redress -help
Usage of redress:
-compiler
Print information
-filepath
Include file path for packages
-force-version string
Forcing and using the given version when analyzing
-interface
Print interfaces
-method
Print type's methods
-pkg
List packages
-src
Print source tree
-std
Include standard library packages
-struct
Print structs
-type
Print all type information
-unknown
Include unknown packages
-vendor
Include vendor packages
-version
Print redress version 🕙[2021-05-05 22:15:51.625] ❯ go install -ldflags="-s -w" ./...
🕙[2021-05-05 22:16:01.530] ❯ ls -lh ~/go/bin/shorturl
-rwxr-xr-x 1 bingoo staff 15M 5 5 22:16 /Users/bingoo/go/bin/shorturl 🕙[2021-05-05 22:15:22.711] ❯ redress -src ~/go/bin/shorturl
Package main: /Users/bingoo/GitHub/shorturl
File: main.go
main Lines: 12 to 22 (10)
Package github.com/bingoohuang/shorturl/pkg: /Users/bingoo/GitHub/shorturl/pkg
File: <autogenerated>
(*noCache)DeactivateURL Lines: 1 to 1 (0)
(*noCache)SavePopularURL Lines: 1 to 1 (0)
(*RedisCache)DeactivateURL Lines: 1 to 1 (0)
(*noCache)LookupURL Lines: 1 to 1 (0)
(*RedisCache)SavePopularURL Lines: 1 to 1 (0)
(*Body)Merge Lines: 1 to 1 (0)
(*URLInput)ValidateExpiry Lines: 1 to 1 (0)
(*RedisCache)LookupURL Lines: 1 to 1 (0)
(*URL)IsActive Lines: 1 to 1 (0)
(*URLInput)GetExpiresOn Lines: 1 to 1 (0)
File: admin.go
ListURLsFilteredFromRequest Lines: 9 to 21 (12)
ListURLsFiltered Lines: 21 to 46 (25)
DeleteURLFromRequest Lines: 46 to 53 (7)
DeleteURLByShortCode Lines: 53 to 65 (12)
File: client.go
CreateURLShortCodeFromRequest Lines: 13 to 25 (12)
CreateURLShortCode Lines: 25 to 55 (30)
LookupOriginURL Lines: 55 to 76 (21)
IncrementHits Lines: 76 to 87 (11)
ValidateURLInput Lines: 87 to 115 (28)
getUniqueShortCode Lines: 115 to 133 (18)
isShortCodeAvail Lines: 133 to 143 (10)
getShortCodeByOriginURL Lines: 143 to 153 (10)
mapKeywords Lines: 153 to 162 (9)
File: config.go
init Lines: 28 to 28 (0)
createDB Lines: 49 to 74 (25)
init0 Lines: 74 to 90 (16)
init.0func1 Lines: 75 to 79 (4)
createEnvName Lines: 90 to 100 (10)
File: controller.go
ListURLs Lines: 10 to 22 (12)
DeleteShortURL Lines: 22 to 33 (11)
CreateShortURL Lines: 33 to 47 (14)
NotFound Lines: 47 to 53 (6)
ServeShortURL Lines: 53 to 68 (15)
File: model.go
URLIsActive Lines: 55 to 100 (45)
(*URLInput)Validate Lines: 100 to 142 (42)
URLInputValidateExpiry Lines: 142 to 164 (22)
URLInputGetExpiresOn Lines: 164 to 173 (9)
URLFilterGetOffset Lines: 173 to 183 (10)
File: redis.go
noCacheLookupURL Lines: 19 to 20 (1)
noCacheDeactivateURL Lines: 20 to 21 (1)
noCacheSavePopularURL Lines: 21 to 29 (8)
CreateRedisCache Lines: 29 to 58 (29)
CreateRedisCachefunc1 Lines: 36 to 37 (1)
RedisCacheLookupURL Lines: 58 to 110 (52)
RedisCacheDeactivateURL Lines: 82 to 93 (11)
RedisCacheSavePopularURL Lines: 93 to 118 (25)
hasURL Lines: 104 to 110 (6)
File: router.go
init1 Lines: 15 to 22 (7)
AssetsRewrite Lines: 22 to 44 (22)
AssetsRewritefunc1 Lines: 23 to 67 (44)
glob.func1 Lines: 34 to 36 (2)
locateHandler Lines: 44 to 66 (22)
RegisterHandlers Lines: 66 to 81 (15)
RegisterHandlersfunc1 Lines: 67 to 83 (16)
Recover Lines: 81 to 94 (13)
Recoverfunc1 Lines: 82 to 95 (13)
Recover.func11 Lines: 83 to 85 (2)
AdminAuth Lines: 94 to 107 (13)
AdminAuthfunc1 Lines: 95 to 102 (7)
validateAdminToken Lines: 107 to 122 (15)
File: util.go
RandomString Lines: 17 to 33 (16)
BodyMerge Lines: 33 to 43 (10)
JSON Lines: 43 to 49 (6) |
延长变量的生命周期 runtime.KeepAlive(v)2019年的一篇文章:https://medium.com/a-journey-with-go/go-keeping-a-variable-alive-c28e3633673a package main
import (
"io/ioutil"
"log"
"os"
"runtime"
"syscall"
)
type File struct{ d int }
func main() {
file, err := ioutil.TempFile("", "keepalive")
if err != nil {
log.Fatal(err)
}
file.Write([]byte("keepalive"))
file.Close()
defer os.Remove(file.Name())
p := openFile(file.Name())
content := readFile(p.d)
// Ensure p is not finalized until Read returns
// runtime.KeepAlive(p)
println("Here is the content: " + content)
}
func openFile(path string) *File {
d, err := syscall.Open(path, syscall.O_RDONLY, 0)
if err != nil {
panic(err)
}
p := &File{d}
runtime.SetFinalizer(p, func(p *File) {
syscall.Close(p.d)
})
return p
}
func readFile(descriptor int) string {
doSomeAllocation()
var buf [1000]byte
_, err := syscall.Read(descriptor, buf[:])
if err != nil {
panic(err)
}
return string(buf[:])
}
func doSomeAllocation() {
var a *int
// memory increase to force the GC
for i := 0; i < 10000000; i++ {
i := 1
a = &i
}
_ = a
} 输出: panic: device not configured
goroutine 1 [running]:
main.readFile(0x3, 0x43, 0xc000120010)
/Users/bingoo/GitHub/gogotcha/cmd/keepalive/main.go:51 +0x138
main.main()
/Users/bingoo/GitHub/gogotcha/cmd/keepalive/main.go:23 +0x176
加上 Here is the content: keepalive |
Go的 50 度灰:Golang 新开发者要注意的陷阱和常见错误50 度灰,先看书后观影 《五十度灰》(英语:Fifty Shades of Grey)是一部2015年上映的美国情色爱情电影,根据EL·詹姆丝的同名小说改编而成。由萨姆·泰勒-约翰逊执导,凯利·马塞尔编剧,并由达科塔·约翰逊、詹米·多南、珍妮佛·艾莉以及马西雅·盖·哈登主演[6]。电影于2015年2月11日在柏林国际电影节上首映[7],2月13日正式公映。票房获得即时的佳绩,打破了多个票房纪录,全球票房5.71亿美元。 |
用组合实现继承继承,直达问题的本质,清晰易懂type Foo struct {
Base // 继承
...
} type Foo struct {
*Base // 虚拟继承
...
} 来源,许式伟, Go vs. GoPlus(Go+) 2021-6-27 北京 GopherChina2021 |
|
Sealed Interfaces 密封接口看到一种 go 代码,接口里定义一个私有无参无返回值的方法,感觉是一种惯用法,原来是密封接口,保证这个接口不给外部去实现。 // Statement represents a statement.
type Statement interface {
iStatement()
SQLNode
}
func (*Union) iStatement() {}
func (*Select) iStatement() {}
func (*Insert) iStatement() {}
func (*Update) iStatement() {}
func (*Delete) iStatement() {}
func (*Set) iStatement() {}
func (*DDL) iStatement() {}
func (*Show) iStatement() {}
func (*Use) iStatement() {}
func (*OtherRead) iStatement() {}
func (*OtherAdmin) iStatement() {}
func (*TruncateTable) iStatement() {} 同样的 // SelectStatement any SELECT statement.
type SelectStatement interface {
iSelectStatement()
iStatement()
iInsertRows()
AddOrder(*Order)
SetLimit(*Limit)
SQLNode
}
func (*Select) iSelectStatement() {}
func (*Union) iSelectStatement() {}
func (*ParenSelect) iSelectStatement() {} |
所有模型都是错误的,但有些模型是有用的在 go-profiler-notes 上看到一句话: All models are wrong
我认为最好通过两部分来分析它的含义: “所有模型都是错误的”,也就是说,每个模型都是错误的,因为它是对现实的简化。一些模型,特别是在“硬”科学中,只是有点错误。他们无视摩擦或微小物体的引力作用。其他模型有很多错误-他们忽略了更大的事情。在社会科学中,我们忽略了很多。 “但是有些有用”-简化现实可能非常有用。它们可以帮助我们解释,预测和理解宇宙及其所有组成部分。 这不仅在统计上是正确的!地图是一种模型。他们错了。但是好的地图非常有用。其他有用但错误的模型的例子比比皆是。 比例为1:1的完美地图的幻想已被许多作者使用,包括Lewis Carroll,Jorge Luis Borges和Umberto Eco。实际上,这没有用,因为它所映射的区域必然很复杂,而且不容易理解(更不用说将其展开并布置为阅读的尴尬了)。 也许您还可以补充一点,就是模型必须有点错误,因为否则它将无法泛化,因此无法在其他地方应用。有一些答案说明了这一点。但是现在有太多的答案无法全部阅读。 对我来说,真正的见解在于以下方面:
不幸的是,在许多科学中,人们常常忘记了模型不一定必须是现实的精确表示即可允许新的发现和预测! 因此,不要浪费您的时间来构建需要对无数变量进行准确测量的复杂模型。真正的天才发明了可以完成这项工作的简单模型。 |
unsafe.Pointer and uintptrpackage main
import "unsafe"
func f() {
var p uintptr
for i := range [10]int{} {
var x = i
if i == 0 {
// uintptr类型的临时变量只是一个普通的数字,所以其值不应该被改变。
// 因此,x 变量在栈上,10次循环,所使用的栈地址不变,因此 p 最后的值是9
p = uintptr(unsafe.Pointer(&x))
}
}
println(*(*int)(unsafe.Pointer(p))) // 9
}
func g() {
var p unsafe.Pointer
for i := range [10]int{} {
var x = i
if i == 0 {
// 从gc视角来看,unsafe.Pointer是一个指向变量的指针,因此当变量被移动是对应的指针也必须被更新
// 为了跟踪指针更新, x 逃逸到了堆上,10次循环,生成了10个不同的x堆变量, p指向了第1个,其值是0
p = unsafe.Pointer(&x)
}
}
println(*(*int)(p)) // 0
}
func main() {
f()
g()
} $ go run -gcflags="-m" p.go
# command-line-arguments
./p.go:19:7: moved to heap: x
9
0
此例,即考察了 |
A先生和S先生,是谁,谷歌一下,原来都是大神啊,大神说的话,应该选择相信。
我摘抄在这里,是想说,我深有同感。我总是从单一的 main.go 开始,随着功能的增加,再分拆结构,也可能一个 main.go 文件就可以了,特别是在制作一些小工具的时候。 |
go1.18 泛型变快了嘛?Credit: https://unsplash.com/photos/CpkOjOcXdUY 看博客Go is about to get a whole lot faster 源代码: 操作步骤:
结果输出: $ go install golang.org/x/tools/cmd/benchcmp@latest
➜ deque more generic.txt
goos: darwin
goarch: amd64
pkg: github.com/sekoyo/deque
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkPushFront-12 97286768 12.28 ns/op
BenchmarkPushBack-12 142144150 14.43 ns/op
BenchmarkSerial-12 100000000 11.82 ns/op
BenchmarkSerialReverse-12 100000000 11.21 ns/op
BenchmarkRotate-12 56238 120075 ns/op
BenchmarkInsert-12 36441 120364 ns/op
BenchmarkRemove-12 107545 119688 ns/op
BenchmarkYoyo-12 1777 675390 ns/op
BenchmarkYoyoFixed-12 2662 455608 ns/op
PASS
ok github.com/sekoyo/deque 33.914s
➜ deque more non.txt
goos: darwin
goarch: amd64
pkg: github.com/gammazero/deque
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkPushFront-12 25286799 50.48 ns/op
BenchmarkPushBack-12 28099020 41.14 ns/op
BenchmarkSerial-12 25631952 50.65 ns/op
BenchmarkSerialReverse-12 26357466 50.56 ns/op
BenchmarkRotate-12 40188 119641 ns/op
BenchmarkInsert-12 28888 120136 ns/op
BenchmarkRemove-12 87488 123670 ns/op
BenchmarkYoyo-12 574 2039762 ns/op
BenchmarkYoyoFixed-12 877 1382135 ns/op
PASS
ok github.com/gammazero/deque 28.086s
➜ deque benchcmp none.txt generic.txt
benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat
benchmark old ns/op new ns/op delta
BenchmarkPushFront-12 50.5 12.3 -75.67%
BenchmarkPushBack-12 41.1 14.4 -64.92%
BenchmarkSerial-12 50.6 11.8 -76.66%
BenchmarkSerialReverse-12 50.6 11.2 -77.83%
BenchmarkRotate-12 119641 120075 +0.36%
BenchmarkInsert-12 120136 120364 +0.19%
BenchmarkRemove-12 123670 119688 -3.22%
BenchmarkYoyo-12 2039762 675390 -66.89%
BenchmarkYoyoFixed-12 1382135 455608 -67.04%
➜ deque more none-go1.17.6.txt
goos: darwin
goarch: amd64
pkg: github.com/gammazero/deque
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkPushFront-12 24497521 50.09 ns/op
BenchmarkPushBack-12 32226673 39.35 ns/op
BenchmarkSerial-12 28485412 46.10 ns/op
BenchmarkSerialReverse-12 27771453 46.76 ns/op
BenchmarkRotate-12 40466 121028 ns/op
BenchmarkInsert-12 28731 121774 ns/op
BenchmarkRemove-12 86724 125651 ns/op
BenchmarkYoyo-12 620 2049784 ns/op
BenchmarkYoyoFixed-12 820 1389294 ns/op
PASS
ok github.com/gammazero/deque 28.335s 还真是,在 PushFront 上竟然快了 75%,看来等 1.18 正式发布了,还是要香一下的。 |
Go 可执行文件大小 树图分析
|
在线火焰图Pyroscope Go Playground |
有名返回参数的坑
package main
func aaa() (done func(), err error) {
return func() {
print("aaa: done")
}, nil
}
func bbb() (done func(), _ error) {
done, err := aaa()
return func() {
print("bbb: surprise!")
done()
}, err
}
func main() {
done, _ := bbb()
done()
} 这个程序输出结果是什么呢,(单选)?
正确答案是:D,程序最终运行出错。一直调用一直爽,直至栈溢出程序崩溃。 他会不断地递归,疯狂输出 “bbb: surprise!”,直至栈溢出,导致程序运行出错,最终中止。 同学就疑惑了,怎么又多出了个递归? 本质上在函数 bbb 执行完毕后, 变量 done 已经变成了一个递归函数。 递归的过程是:函数 bbb 调用变量 done 后,会输出 bbb: surprise! 字符串,然后又调用变量 done。而变量 done 又是这个闭包(匿名函数),从而实现不断递归调用和输出。 总结这位大佬出的题目,本质上是比较烦人的,其结合了函数返回参数的命名用法。 如果我们把这个函数的返回参数命名去掉,就可以避开这个问题。 |
GO 语言纪录片 |
详解 Go 中的 rune 类型https://mp.weixin.qq.com/s/hcrq5fYaQ7FN_2oSMRNjcA Go 语言把字符分 byte 和 rune 两种类型处理。byte 是类型 unit8 的别名,用于存放占 1 字节的 ASCII 字符,如英文字符,返回的是字符原始字节。rune 是类型 int32 的别名,用于存放多字节字符,如占 3 字节的中文字符,返回的是字符 Unicode 码点值。如下图所示: s := "Go语言编程"
// byte
fmt.Println([]byte(s)) // 输出:[71 111 232 175 173 232 168 128 231 188 150 231 168 139]
// rune
fmt.Println([]rune(s)) // 输出:[71 111 35821 35328 32534 31243] |
docker 编译Dockerfile: FROM golang:alpine AS builder
WORKDIR /build
RUN apk add upx
COPY . .
RUN go build -ldflags "-s -w" -o hello hello.go && upx hello
FROM alpine
WORKDIR /build
COPY --from=builder /build/hello /build/hello
CMD ["./hello"]
$ docker run -it --rm hello:v1
hello world!
$ docker run -it --rm hello:v1 ls -lh /build
total 332K
-rwxr-xr-x 1 root root 331.2K Mar 15 02:12 hello
$ docker images | grep hello
hello v1 b3762d8a6c76 12 minutes ago 5.92MB |
源代码特洛伊木马攻击~/aaa ❯ go install github.com/breml/bidichk/cmd/bidichk@latest
~/aaa 38s ❯ more a.go 14:49:52
package main
import "fmt"
func main() {
str, mask := "Hello, World!<U+202E>10x<U+202D>", 0
bits := 0
for _, ch := range str {
for ch > 0 {
bits += int(ch) & mask
ch = ch >> 1
}
}
fmt.Println("Total bits set:", bits)
}
~/aaa ❯ bidichk a.go 14:49:56
/Users/bingoobjca/aaa/a.go:6:29: found dangerous unicode character sequence RIGHT-TO-LEFT-OVERRIDE
/Users/bingoobjca/aaa/a.go:6:35: found dangerous unicode character sequence LEFT-TO-RIGHT-OVERRIDE https://goplay.tools/snippet/2Ty5h65xSjv package main
import "fmt"
func main() {
str := "Hello, World!1234567890"
fmt.Println(str)
} Output: Hello, World!1234567890 |
package main
import "fmt"
func main() {
//str, mask := "Hello, World!10x", 0
str, mask := "Hello, World!<U+202E>10x<U+202D>", 0
bits := 0
for _, ch := range str {
for ch > 0 {
bits += int(ch) & mask
ch = ch >> 1
}
}
fmt.Println("Total bits set:", bits)
str1 := "Hello, World!12345678901 ;"
fmt.Println(str1)
str2 := "Hello, World!12345678901 "
fmt.Println(str2)
} resultTotal bits set: 0 Program exited. |
为什么是 int 类型package main
import (
"fmt"
)
func main() {
v := 4
fmt.Printf("%T\n", v)
f := ((v / 5.0) * 100.0) * 11.0 / 100.0
fmt.Printf("Type of result %T for value %0.2f\n", f, f)
fmt.Printf("\n%T\n", 4)
f2 := ((4 / 5.0) * 100.0) * 11.0 / 100.0
fmt.Printf("Type of result %T for value %0.2f\n", f2, f2)
} 输出结果: int
Type of result int for value %!f(int=00)
int
Type of result float64 for value 8.80 |
GO 从源代码到可执行文件的编译过程:连接时,会打上运行时 |
https://mp.weixin.qq.com/s/bg3LarfaiSKvs5U4mgnEEg Go Team为Gopher负重前行! 这是在X.com上看到一幅图片,从中可以看出Go team为Gopher的“just write business logic”而负重前行。 就像我在《Go语言精进之路》第一卷中所说的那样:“Go的设计者们在语言设计之初就拒绝走语言特性融合的道路,而选择了“做减法”。并且他们把复杂性留给了语言自身的设计和实现,留给了Go Team自己;而将简单、易用和清晰留给了广大Gopher”。让广大Gopher可以用简单的语法聚焦于编写business logic的代码上。 |
Golang多版本安装
method1 官方
$ go get -u golang.org/dl/go1.12.3 go: finding golang.org/dl latest go: downloading golang.org/dl v0.0.0-20190408222801-b337094d5ff3 go: extracting golang.org/dl v0.0.0-20190408222801-b337094d5ff3 $ go1.12.3 download Downloaded 100.0% (127615731 / 127615731 bytes) Unpacking /Users/bingoobjca/sdk/go1.12.3/go1.12.3.darwin-amd64.tar.gz ... Success. You may now run 'go1.12.3' $ go1.12.3 version go version go1.12.3 darwin/amd64 $ go version go version go1.12.1 darwin/amd64
method2 gvm
install
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
influxdb推荐使用gvm来构建:
The text was updated successfully, but these errors were encountered: