ショック! Go にはとても素敵な機能があります。
まず第一に、Lao Xu は他の人たちの評価に感謝したいと思います。これが私がそれを楽しむための動機です。同時に反省も必要です。この若い女性はまだ比較的機敏ですが、私たちの四川弁では、前の記事のタイトルは実際には cuo
です。
何度も考えた後、Lao Xu は注目を集めることに決め、「衝撃的! Go にはこんなに素晴らしい小さな機能があります! 」という二重の感嘆符を付けて名前を付けました。タイトルにはあまり当てはまらないいくつかの小さな機能を見てみましょう。
a/bを四捨五入して最も近い整数に戻す
func divRoundUp(n, a uintptr) uintptr { return (n + a - 1) / a }
この方法を使ったことがある人は多いはずで、最も代表的なのはページング計算です。
x が 2 の n 乗であるかどうかを判断します
func isPowerOfTwo(x uintptr) bool { return x&(x-1) == 0 }
これも非常に理解しやすいですが、唯一注意すべき点は、x は 0 より大きい必要があるということです。 , 方程式 0 も成り立つからです。
x を a の倍数に四捨五入します。a は 2 の n 乗でなければなりません
// 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为8 func alignUp(x, a uintptr) uintptr { return (x + a - 1) &^ (a - 1) } // 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为4 func alignDown(x, a uintptr) uintptr { return x &^ (a - 1) }
在这里老许再次明确一个概念,2的n次幂即为1左移n位
。然后上述代码中^
为单目运算法按位取反,则^ (a - 1)
的运算结果是除了最低n位为0其余位全为1。剩余的部分则是一个简单的加减运算以及按位与。
上述代码分开来看每一部分都认识,合在一起就一脸懵逼了。幸运的是,经过老许的不懈努力终于找到了一种能够理解的方式。
例として x=10、a=4
を取り上げます。 a
は 2 の 2 乗、つまり 1 が 2 ビット左にシフトされます。 #xx は 2 つの部分の合計として見ることができます。最初の部分 x1 は
0b1000、2 番目の部分 x2 は
0b0011 です。 #xx
の分割方法は、n
ビットを左に 1 シフトして a
を取得することによって決定されます。つまり、x の最下位 n ビットは x2 と x1 です。 x-x2です。したがって、x1 は 0b10 を 2 ビット左にシフトしたものに相当します。つまり、x1 はすでに a の整数倍です。このとき、x2 が 0 より大きい限り、x2 a-1 は必ず 1 つ進みます。 ##x1 1 または
x1 a の整数倍を x で切り上げただけではありませんか? 最後に
^ (a - 1)## で AND 演算を実行します。 # 最下位 2 ビットをクリアして、最終的な戻り結果を取得します。 一つ言っておきますが、私にはそのようなロジックは絶対に書けません。そのため、偉い人たちがコンピューターについて非常に優れた理解を持っていることを嘆かざるを得ません。このような機能は素晴らしいものですが、実際の開発ではできるだけ使用しないほうがよいでしょう。 1つは利用シーンに制限があること(aは2のn乗でなければならない)、もう1つはスキルを披露したり見せびらかす以外にはわかりにくいこと(よほどの高い性能要求を除く)。
// bool2int returns 0 if x is false or 1 if x is true. func bool2int(x bool) int { return int(uint8(*(*uint8)(unsafe.Pointer(&x)))) }
如果让我来写这个函数,一个稀松平常的switch
就完事儿,现在我又多了一种装逼的套路。老许在这里特别友情提示,字节切片和字符串也可使用上述方式进行相互转换。
计算不同类型最低位0的位数
var ntz8tab = [256]uint8{ 0x08, ..., 0x00, } // Ctz8 returns the number of trailing zero bits in x; the result is 8 for x == 0. func Ctz8(x uint8) int { return int(ntz8tab[x]) } const deBruijn32ctz = 0x04653adf var deBruijnIdx32ctz = [32]byte{ 0, 1, 2, 6, 3, 11, 7, 16, 4, 14, 12, 21, 8, 23, 17, 26, 31, 5, 10, 15, 13, 20, 22, 25, 30, 9, 19, 24, 29, 18, 28, 27, } // Ctz32 counts trailing (low-order) zeroes, // and if all are zero, then 32. func Ctz32(x uint32) int { x &= -x // isolate low-order bit y := x * deBruijn32ctz >> 27 // extract part of deBruijn sequence i := int(deBruijnIdx32ctz[y]) // convert to bit index z := int((x - 1) >> 26 & 32) // adjustment if zero return i + z } const deBruijn64ctz = 0x0218a392cd3d5dbf var deBruijnIdx64ctz = [64]byte{ 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15, 46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39, 16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43, 51, 60, 42, 59, 58, } // Ctz64 counts trailing (low-order) zeroes, // and if all are zero, then 64. func Ctz64(x uint64) int { x &= -x // isolate low-order bit y := x * deBruijn64ctz >> 58 // extract part of deBruijn sequence i := int(deBruijnIdx64ctz[y]) // convert to bit index z := int((x - 1) >> 57 & 64) // adjustment if zero return i + z }
Ctz8
、Ctz32
和Ctz64
分别计算无符号8、32、64位数最低位为0的个数,即某个数左移的位数。
函数的作用通过翻译倒是能理解,我也能深刻的明白这是典型的空间换时间,然而要问一句为什么我是万万答不上来的。不过老许已经替你们找好了答案,原因就藏在这篇Using de Bruijn Sequences to Index a 1 in a Computer Word论文中。欢迎巨佬们去挑战一下,而我只想坐享其成,那么在巨佬们分析完这篇论文之前就让这些函数安家在我的收藏栏里方便以后炫技。
这里特别说明,术业有专攻,我们不一定要所有东西都会,但要尽可能知道有这么一个东西存在。这即是老许为自己找的一个不去研究此论文的接口,也是写下此篇文章的意义之一(万一有人提到了Bruijn Sequences
关键词,我们也不至于显得过分无知)。
math/bits包中的部分函数
如果有人知道这个包,那请原谅我的无知直接跳过本部分即可。老许发现这个包是源于ntz8tab
变量所在文件runtime/internal/sys/intrinsics_common.go
中的一句注释。
// Copied from math/bits to avoid dependence.
作为一个资深的CV工程师, 看到这句的第一反应就是我终于可以挺直腰杆了。适当Copy代码不丢人!
math/bits
这个包函数较多,老许挑几个介绍即可,其余的还请各位读者自行挖掘。
LeadingZeros(x uint) int
: 返回x所有高位为0的个数。
TrailingZeros(x uint) int
: 返回x最低位为0的个数。
OnesCount(x uint) int
:返回x中bit位为1的个数。
Reverse(x uint) uint
: 将x按bit位倒序后再返回。
Len(x uint) int
: 返回表示x的有效bit位个数(高位中的0不计数)。
ReverseBytes(x uint) uint
: 将x按照每8位一组倒序后返回。
将x逃逸至堆
// Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. func escapes(x interface{}) { if dummy.b { dummy.x = x } } var dummy struct { b bool x interface{} }
老许是在reflect.ValueOf
函数中发现此函数的调用,当时就觉着挺有意思。如今再次回顾也依旧佩服不已。读书是和作者的对话,阅读源码是和开发者的对话,看到此函数就仿佛看到Go语言开发者们和编译器斗智斗勇的场景。
让出当前Processor
// Gosched yields the processor, allowing other goroutines to run. It does not // suspend the current goroutine, so execution resumes automatically. func Gosched() { checkTimeouts() mcall(gosched_m) }
让出当前的Processor,允许其他goroutine执行。在实际的开发当中老许还未遇到需要使用此函数的场景,但多了解总是有备无患。
以上がショック! Go にはとても素敵な機能があります。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go では、関数のライフ サイクルには定義、ロード、リンク、初期化、呼び出し、戻り値が含まれます。変数のスコープは関数レベルとブロック レベルに分割されますが、ブロック内の変数はブロック内でのみ表示されます。 。

Go では、正規表現を使用してタイムスタンプを照合できます。ISO8601 タイムスタンプの照合に使用されるような正規表現文字列をコンパイルします。 ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。 regexp.MatchString 関数を使用して、文字列が正規表現と一致するかどうかを確認します。

Go では、gorilla/websocket パッケージを使用して WebSocket メッセージを送信できます。具体的な手順: WebSocket 接続を確立します。テキスト メッセージを送信します。 WriteMessage(websocket.TextMessage,[]byte("message")) を呼び出します。バイナリ メッセージを送信します。WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) を呼び出します。

Go と Go 言語は、異なる特性を持つ別個の存在です。 Go (Golang とも呼ばれます) は、同時実行性、高速なコンパイル速度、メモリ管理、およびクロスプラットフォームの利点で知られています。 Go 言語の欠点としては、他の言語に比べてエコシステムが充実していないこと、構文が厳格であること、動的型付けが欠如していることが挙げられます。

メモリ リークは、ファイル、ネットワーク接続、データベース接続などの使用されなくなったリソースを閉じることによって、Go プログラムのメモリを継続的に増加させる可能性があります。弱参照を使用してメモリ リークを防ぎ、強参照されなくなったオブジェクトをガベージ コレクションの対象にします。 go coroutine を使用すると、メモリ リークを避けるために、終了時にコルーチンのスタック メモリが自動的に解放されます。

IDE を使用して Go 関数のドキュメントを表示する: 関数名の上にカーソルを置きます。ホットキーを押します (GoLand: Ctrl+Q; VSCode: GoExtensionPack をインストールした後、F1 キーを押して「Go:ShowDocumentation」を選択します)。

Golang では、エラー ラッパーを使用して、元のエラーにコンテキスト情報を追加することで新しいエラーを作成できます。これを使用すると、さまざまなライブラリまたはコンポーネントによってスローされるエラーの種類を統一し、デバッグとエラー処理を簡素化できます。手順は次のとおりです。errors.Wrap 関数を使用して、元のエラーを新しいエラーにラップします。新しいエラーには、元のエラーのコンテキスト情報が含まれています。 fmt.Printf を使用してラップされたエラーを出力し、より多くのコンテキストとアクション性を提供します。異なる種類のエラーを処理する場合は、errors.Wrap 関数を使用してエラーの種類を統一します。

並行関数の単体テストは、同時環境での正しい動作を確認するのに役立つため、非常に重要です。同時実行機能をテストするときは、相互排他、同期、分離などの基本原則を考慮する必要があります。並行機能は、シミュレーション、競合状態のテスト、および結果の検証によって単体テストできます。
