l = [] for i inrange(3): s = "prefix-" + str(i) definner_f(i, s): print('i: {} ({}), s: {} ({})'.format(i, id(i), s, id(s))) # 使用 partial 将二元谓词 inner_f 的两个参数绑定为 i 和 s 的值 l.append(partial(inner_f, i, s))
l = [] for i inrange(3): s = "prefix-" + str(i) l.append( lambda i=i, s=s: print("i: {} ({}), s: {} ({})".format(i, id(i), s, id(s))) ) for f in l: f()
l = [] for i inrange(3): s = "prefix-" + str(i) l.append( lambda inner_i=i, inner_s=s: print( "i: {} ({}), s: {} ({})".format(inner_i, id(inner_i), inner_s, id(inner_s)) ) ) for f in l: f()
"pool-1-thread-1" #11 prio=5 os_prio=31 tid=0x00007fa04392a000 nid=0xa603 waiting on condition [0x0000700004bd6000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000076b1778a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
publicThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))
设置 Go 环境变量的方式:
1
$ go env -w GOBIN=$PWD
这样就会安装到当前目录(注意这只是示例,而且会永久生效,最好改到需要的路径)。如果要取消 Go 环境变量,使用 -u 选项即可:
1
$ go env -u GOBIN
从 module 中导入 package
创建子目录 *morestrings/*,然后在该目录下创建文件 reverse.go:
1 2 3 4 5 6 7 8 9 10 11 12
// Package morestrings implements additional functions to manipulate UTF-8 // encoded strings, beyond what is provided in the standard "strings" package. package morestrings
// ReverseRunes returns its argument string reversed rune-wise left to right. funcReverseRunes(s string)string { r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } returnstring(r) }
进入该目录,运行 go build,可以发现不会生成文件,但实际上已经编译到本地 build cache 里了。
rune:int32 的别名,它表示一个 Unicode 码点,因为对于 ASCII 字符串而言,基本单位是 int8(也就是 char),但是 Go 对字符串只支持 Unicode 编码,因此没有使用 char 关键字,而是使用 rune,代表一个 Unicode 字符。因此在 Go 里,字符和字节不会混淆。
浮点数:float32,float64
复数:complex64,complex128。
Go 保证变量不赋予初值的话,默认是零值。数值类型都是 0,布尔类型是 false,字符串是空字符串 ""(注意不是 空值nil)。
Go 的变量初始化可以推断类型,整型默认为 int,浮点数类型默认为 float64,如果没有初始值,则必须显式注明类型。此外初始化还支持 := 这种形式(但是必须在函数体内使用),比如:
1 2 3 4
var x = 10 var y int y = x + 10 z := 30
常量(const 修饰)因为必须有初值,所以基本可以省略类型声明。
Go 的格式化打印不是很灵活,只支持 C 风格的格式化字符串(使用 fmt.Printf)或者直接打印任意类型(使用 fmt.Println 或 fmt.Print)。但是在 C 风格打印时,Go 支持 %T 打印类型名,%v 打印任何类型,还能用 %#v 对类型本身进行修饰,比如:
1
fmt.Printf("%T x = %v, %T y = %#v\n", x, x, y, y)
打印的是 int x = 10, string y = "hello",注意如果不用 %#v 的话,不会给字符串加上引号。
Go 的类型转换有点像函数调用,比如 T(v) 将 v 转换成类型 T。Go 没有隐式类型转换,因此即使将 int32 转换成 int 也要显式进行,比如:
1 2
var x int32 = 1 var y int = int(x)
Go 的循环只支持 for 循环,循环体必须有大括号,而初始化(可选),条件判断以及后置语句(可选)的部分则不用。if 也类似。比如:
1 2 3 4 5
for i := 0; i < 100; i++ { if i%3 == 0 { fmt.Println(i) } }
无限循环可以缩写为
1 2 3
for { // ... }
if 也支持初始化,并且初始化语句的值可以在 else 分支使用,比如:
1 2 3 4 5 6
var x int = 100 if y := x / 2; y%2 == 0 { fmt.Println(y) } else { fmt.Println(y) }
注意在 for 和 if 的初始化语句里,只能用 := 的形式,因此要声明类型必须对 := 右边的表达式进行类型转换。另外,Go 虽然也支持 else if,但这种情况下,最好使用 switch。Go 的 switch 默认不会 fallthrough,因此不需要对每个分支加 break。
switch 比较灵活,其实更类似把 if 语句做个包装,比如:
1 2 3 4 5 6 7 8
switch x := 1; true { // switch <initialize>; <variable> case x < 0: fmt.Println("x < 0") case x == 0: fmt.Println("x = 0") case x > 0: fmt.Println("x > 0") }
这里的 true 可以省略(因为默认的 <variable> 就是 true),比如上面代码可以改为 switch x := 1; {。这里我这么写实际上想表达,上面语句是将 true 与下面的 case 后接的表达式(比如 x < 0)求值依次进行比较。
这次重新学习的时候,差点以为 Go 的 switch 语句像 Scala,Rust 的模式匹配一样强大,实际上,虽然也比较强大就是了。
数组,切片,映射都是引用语义,因此想要修改内部时,不必传递指针。默认值都是 nil,也就是底层为空,但是像 len 和 cap 都能成功调用并返回 0。
Go 的数组也类似 C,即是定长数组比如 [n]T,表示数组元素类型为 T,数量为 n ,也可以采用大括号初始化的方式:
1
x := [5]int{1, 1, 2, 3, 5}
注意,Go 的数组不像 C 一样可以推断出数组长度,如果你写成了下面这样:
1
x := []int{1, 1, 2, 3, 5}
此时 x 的类型是切片([]int)而非数组([5]int)。相比数组而言,切片可以动态增长,类似 C++ 的 vector,因此对于切片 x,可以用 cap(x) 取得切片 x 的容量,len(x) 取得切片的长度,以及用 make 进行初始化(make(<type>, <len>) 或者 make(<type>, <len>, <cap>),用 append 添加元素。但这些都是 Go 的内置函数。
funcmain() { sum := AddOperation{}.Calculate(1, 2) fmt.Println(sum.(int)) }
如果要支持多种类型,比如 float,就得利用t, ok := i.(T) 的形式了,但是可以用 switch 进行简化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
func(op AddOperation) Calculate(x, y interface{}) interface{} { switch vx := x.(type) { caseint: if vy, ok := y.(int); ok { return vx + vy } else { panic("x is int while y is not int") } casefloat64: if vy, ok := y.(float64); ok { return vx + vy } else { panic("x is int while y is not int") } default: panic("x is not int or float64") } }
2021-08-2023:15:55:264 [main] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information. Recent access records: #1: io.netty.buffer.AdvancedLeakAwareByteBuf.readByte(AdvancedLeakAwareByteBuf.java:400) ...
ForkJoinPool.commonPool-worker-9 in firstFuture, x = -1634409183 main in secondFuture, firstFuture returns -1634409183 main secondFuture returns: -817204591
1 2 3
ForkJoinPool.commonPool-worker-9in firstFuture, x = 1243845674 mainin secondFuture, firstFuture returns 1243845674 main secondFuture failed: java.lang.Exception: firstFuture returns an even number: 1243845674
ForkJoinPool.commonPool-worker-9in firstFuture, x = 784152994 mainin secondFuture exception: java.util.concurrent.CompletionException: java.lang.RuntimeException: firstFuture returns an even number: 784152994 main secondFuture returns: null
private <V> CompletableFuture<V> uniApplyStage( Executor e, Function<? super T,? extends V> f) { // f 即用户传入的 T -> U 的 lambda 表达式,这里泛型参数是 V 而不是 U if (f == null) thrownewNullPointerException(); CompletableFuture<V> d = newCompletableFuture<V>(); // 注意这里的 e 是 Executor 对象,而不是异常,因为 f 并没有执行 if (e != null || !d.uniApply(this, f, null)) { UniApply<T,V> c = newUniApply<T,V>(e, d, this, f); push(c); c.tryFire(SYNC); // SYNC 是常量 0 } return d; }
ForkJoinPool.commonPool-worker-9 supplyAsync, x = 1489321475 main whenComplete integer=1489321475, throwable=null
1 2
ForkJoinPool.commonPool-worker-9 supplyAsync, x = -1124011744 main whenComplete integer=null, throwable=java.util.concurrent.CompletionException: java.lang.RuntimeException: firstFuture returns an even number: -1124011744