Go Code Review Comments 译文

2023-10-31

持续更新中…
原文最新链接
https://github.com/golang/go/wiki/CodeReviewComments/5a40ba36d388ff1b8b2dd4c1c3fe820b8313152f
Github译文链接
https://github.com/wddpct/articles/issues/8

对于刚开始学习和使用 Go 的新手来说,有这么几个资源值得关注。

  1. A Tour of Go
  2. How to Write Go Code
  3. Frequently Asked Questions (FAQ)
  4. The Go Blog Index
  5. The Go Wiki
  6. Effective Go
  7. Go Code Review Comments
  8. ……

Effective Go 和 Go Code Review Comments 中介绍了很多有助于编写优雅,高效的 Go 代码的指导性原则,前者可以认为是官方权威指南,而后者则可以算是对前者的补充,原文托管在 Github 上,每个月都会做部分 fix,而网上的中文版大多都是历史版本,无法及时更新,所以想由自己在业余时做些额外的工作,水平一般,能力有限,少部分难以翻译的词句将附上原文或给出意译内容。以下是翻译正文。


Go Code Review Comments

当前页面收集了在 Go 代码审核期间的常见意见,以便一个详细说明能被快速参考。这是一个常见错误的清单,而非综合性的风格指南。

你也可以将它作为是 Effective Go 的补充。

请在编辑这个页面前先讨论这个变更,就算是一个很小的变更。毕竟许多人都有自己的想法,而这里并不是战场。

Gofmt

在 Go 代码上运行 gofmt 以自动修复大多数的机械性风格问题。几乎所有不正规的 Go 代码都在使用gofmt。本文档的剩余部分涉及非机械性风格问题。

另一种方法是使用 goimports,这是gofmt的超集,gofmt可根据需要额外添加(和删除)导入行。

Comment Sentences

参见 https://golang.org/doc/effective_go.html#commentary。注释文档声明应该是完整的句子,即使这看起来有些多余。这种方式使注释在提取到 godoc 文档时格式良好。注释应以所描述事物的名称开头,并以句点结束:

// Request represents a request to run a command.
type Request struct { ...

// Encode writes the JSON encoding of req to w.
func Encode(w io.Writer, req *Request) { ...

请注意除了句点之外还有其他符号可以作为句子的有效结尾(但至少也应该是!,?)。除此之外,还有许多工具使用注释来标记类型和方法(如 easyjson:json 和 golint 的 MATCH)。这使得这条规则难以形式化。

Contexts

A function that is never request-specific may use context.Background(), but err on the side of passing a Context even if you think you don't need to. The default case is to pass a Context; only use context.Background() directly if you have a good reason why the alternative is a mistake.

context.Context 类型的值包含跨 API 和进程边界的安全凭证,跟踪信息,截止时间和取消信号。比如传入 RPC 请求和 HTTP 请求一直到传出相关请求,Go 程序在整个过程的函数调用链中显式地传递 Context。

大多数使用 Context 的函数都应该接受 Context 作为函数的第一个参数:

func F(ctx context.Context, /* other arguments */) {}

从不特定于请求(request-specific)的函数可以使用 context.Background() 获取 Context,并将 err 与 Context 同时传递,即使你认为不需要。默认情况下只传递 Context ;只在你有充分的理由认为这是错误的,才能直接使用context.Background()。

原文: A function that is never request-specific may use context.Background(), but err on the side of passing a Context even if you think you don't need to. The default case is to pass a Context; only use context.Background() directly if you have a good reason why the alternative is a mistake.

不要将 Context 成员添加到某个 struct 类型中;而是将 ctx 参数添加到该类型的方法上。一个例外情况是当前方法签名必须与标准库或第三方库中的接口方法匹配。

不要在函数签名中创建自定义 Context 类型或使用除了 Context 以外的接口。

如果要传递应用程序数据,请将其放在参数,方法接收器,全局变量中,或者如果它确实应该属于 Context,则放在 Context 的 Value 属性中。

所有的 Context 都是不可变的,因此可以将相同的 ctx 传递给多个共享相同截止日期,取消信号,安全凭据,跟踪等的调用。

Copying

为避免意外的别名,从另一个包复制 struct 时要小心。例如,bytes.Buffer 类型包含一个 []byte 的 slice,并且作为短字符串的优化,slice 可以引用一个短字节数组。如果复制一个 Buffer,副本中的 slice 可能会对原始数组进行别名操作,从而导致后续方法调用产生令人惊讶的效果。

通常,如果 T 类型的方法与其指针类型 *T 相关联,请不要复制 T 类型的值。

Crypto Rand

不要使用包math/rand来生成密钥,即使是一次性密钥。在没有种子(seed)的情况下,生成器是完全可以被预测的。使用time.Nanoseconds()作为种子值,熵只有几位。请使用crypto/rand的 Reader 作为替代,如果你倾向于使用文本,请输出成十六进制或 base64 编码:

import (
    "crypto/rand"
    // "encoding/base64"
    // "encoding/hex"
    "fmt"
)

func Key() string {
    buf := make([]byte, 16)
    _, err := rand.Read(buf)
    if err != nil {
        panic(err)  // out of randomness, should never happen
    }
    return fmt.Sprintf("%x", buf)
    // or hex.EncodeToString(buf)
    // or base64.StdEncoding.EncodeToString(buf)
}

Declaring Empty Slices

当声明一个空 slice 时,倾向于用

var t []string

代替

t := []string{}

前者声明了一个 nil slice 值,而后者声明了一个非 nil 但是零长度的 slice。两者在功能上等同,len 和 cap 均为零,而 nil slice 是首选的风格。

请注意,在部分场景下,首选非零但零长度的切片,例如编码 JSON 对象时(前者编码为 null,而后者则可以正确编码为 JSON array[])。

在设计 interface 时,避免区分 nil slice 和 非 nil,零长度的 slice,因为这会导致细微的编程错误。

有关 Go 中对于 nil 的更多讨论,请参阅 Francesc Campoy 的演讲 Understanding Nil

Doc Comments

所有的顶级导出的名称都应该有 doc 注释,重要的未导出类型或函数声明也应如此。有关注释约束的更多信息,请参阅 https://golang.org/doc/effective_go.html#commentary

Don't Panic

请参阅 https://golang.org/doc/effective_go.html#errors。不要将 panic 用于正常的错误处理。使用 error 和多返回值。

Error Strings

Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context. That is, use fmt.Errorf("something bad") not fmt.Errorf("Something bad"), so that log.Printf("Reading %s: %v", filename, err) formats without a spurious capital letter mid-message. This does not apply to logging, which is implicitly line-oriented and not combined inside other messages.

错误信息字符串不应大写(除非以专有名词或首字母缩略词开头)或以标点符号结尾,因为它们通常是在其他上下文后打印的。即使用fmt.Errorf("something bad")而不要使用fmt.Errorf("Something bad"),因此log.Printf("Reading %s: %v", filename, err)的格式中将不会出现额外的大写字母。否则这将不适用于日志记录,因为它是隐式的面向行,而不是在其他消息中组合。

Examples

When adding a new package, include examples of intended usage: a runnable Example, or a simple test demonstrating a complete call sequence.

Read more about testable Example() functions.

添加新包时,请包含预期用法的示例:可运行的示例,或是演示完整调用链的简单测试。

阅读有关 testable Example() functions 的更多信息。

Goroutine Lifetimes

当你生成 goroutines 时,要清楚它们何时或是否会退出。

通过阻塞 channel 的发送或接收可能会引起 goroutines 的内存泄漏:即使被阻塞的 channel 无法访问,垃圾收集器也不会终止 goroutine。

即使 goroutines 没有泄漏,当它们不再需要时却仍然将其留在内存中会导致其他细微且难以诊断的问题。往已经关闭的 channel 发送数据将会引发 panic。在“结果不被需要之后”修改仍在使用的输入仍然可能导致数据竞争。并且将 goroutines 留在内存中任意长时间将会导致不可预测的内存使用。

请尽量让并发代码足够简单,从而更容易地确认 goroutine 的生命周期。如果这不可行,请记录 goroutines 退出的时间和原因。

Handle Errors

请参阅 https://golang.org/doc/effective_go.html#errors。不要使用 _ 变量丢弃 error。如果函数返回 error,请检查它以确保函数成功。处理 error,返回 error,或者在真正特殊的情况下使用 panic。

Imports

Avoid renaming imports except to avoid a name collision; good package names should not require renaming. In the event of collision, prefer to rename the most local or project-specific import.

避免包重命名导入,防止名称冲突;好的包名称不需要重命名。如果发生命名冲突,则更倾向于重命名最接近本地的包或特定于项目的包。

包导入按组进行组织,组与组之间有空行。标准库包始终位于第一组中。

package main

import (
    "fmt"
    "hash/adler32"
    "os"

    "appengine/foo"
    "appengine/user"

    "github.com/foo/bar"
    "rsc.io/goversion/version"
)

goimports 会为你做这件事。

Import Dot

部分包由于循环依赖,不能作为测试包的一部分进行测试时,以.形式导入它们可能很有用:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

在这种情况下,测试文件不能位于 foo 包中,因为它使用的 bar/testutil 依赖于 foo 包。所以我们使用import .形式使得测试文件伪装成 foo 包的一部分,即使它不是。除了这种情况,不要在程序中使用 import .。它将使程序更难阅读——因为不清楚如 Quux 这样的名称是否是当前包中或导入包中的顶级标识符。

In-Band Errors

在 C 和类 C 语言中,通常使函数返回 -1 或 null 之类的值用来发出错误信号或缺少结果:

// Lookup returns the value for key or "" if there is no mapping for key.
func Lookup(key string) string

// Failing to check a for an in-band error value can lead to bugs:
Parse(Lookup(key))  // returns "parse failure for value" instead of "no value for key"

Go 对多返回值的支持提供了一种更好的解决方案。函数应返回一个附加值以指示其他返回值是否有效,而不是要求客户端检查 in-band 错误值。此附加值可能是一个 error,或者在不需要解释时可以是布尔值。它应该是最终的返回值。

// Lookup returns the value for key or ok=false if there is no mapping for key.
func Lookup(key string) (value string, ok bool)

这可以防止调用者错误地使用返回结果:

Parse(Lookup(key))  // compile-time error

并鼓励更健壮和可读性强的代码:

value, ok := Lookup(key)
if !ok  {
    return fmt.Errorf("no value for %q", key)
}
return Parse(value)

此规则适用于公共导出函数,但对于未导出函数也很有用。

返回值如 nil,“”,0 和 -1 在他们是函数的有效返回结果时是可接收的,即调用者不需要将它们与其他值做分别处理。

某些标准库函数(如 “strings” 包中的函数)会返回 in-band 错误值。这大大简化了字符串操作,代价是需要程序员做更多事。通常,Go 代码应返回表示错误的附加值。

Indent Error Flow

Try to keep the normal code path at a minimal indentation, and indent the error handling, dealing with it first. This improves the readability of the code by permitting visually scanning the normal path quickly. For instance, don't write:

尝试将正常的代码路径保持在最小的缩进处,优先处理错误并缩进。通过允许快速可视化扫描正常路径来提高代码的可读性。例如,不要写:

if err != nil {
    // error handling
} else {
    // normal code
}

相反,书写以下代码:

if err != nil {
    // error handling
    return // or continue, etc.
}
// normal code

如果 if 语句具有初始化语句,例如:

if x, err := f(); err != nil {
    // error handling
    return
} else {
    // use x
}

那么这可能需要将短变量声明移动到新行:

x, err := f()
if err != nil {
    // error handling
    return
}
// use x

Initialisms

名称中的单词是首字母或首字母缩略词(例如 “URL” 或 “NATO” )需要具有相同的大小写规则。例如,“URL” 应显示为 “URL” 或 “url” (如 “urlPony” 或 “URLPony” ),而不是 “Url”。举个例子:ServeHTTP 不是 ServeHttp。对于具有多个初始化 “单词” 的标识符,也应当显示为 “xmlHTTPRequest” 或 “XMLHTTPRequest”。

当 “ID” 是 “identifier” 的缩写时,此规则也适用于 “ID” ,因此请写 “appID” 而不是“appId”。

由协议缓冲区编译器生成的代码不受此规则的约束。人工编写的代码比机器编写的代码要保持更高的标准。

Interfaces

Go 接口通常属于使用 interface 类型值的包,而不是实现这些值的包。实现包应返回具体(通常是指针或结构)类型:这样一来可以将新方法添加到实现中,而无需进行大量重构。

不要在 API 的实现者端定义 “for mocking” 接口;相反,设计 API 以便可以使用真实实现的公共 API 进行测试。

在使用接口之前不要定义接口:如果没有真实的使用示例,很难看出接口是否是必要的,更不用说它应该包含哪些方法。

package consumer  // consumer.go

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { … }
package consumer // consumer_test.go

type fakeThinger struct{ … }
func (t fakeThinger) Thing() bool { … }
…
if Foo(fakeThinger{…}) == "x" { … }
// DO NOT DO IT!!!
package producer

type Thinger interface { Thing() bool }

type defaultThinger struct{ … }
func (t defaultThinger) Thing() bool { … }

func NewThinger() Thinger { return defaultThinger{ … } }

相反,返回一个具体的类型,让消费者模拟生产者实现。

package producer

type Thinger struct{ … }
func (t Thinger) Thing() bool { … }

func NewThinger() Thinger { return Thinger{ … } }

Line Length

Go代码中没有严格的行长度限制,但避免使用造成阅读障碍的长行。类似的,如果长行的可读性更好,不要为了缩短行而添加换行符——例如,行组成是重复的。

大多数情况下,当人们 “不自然地” 自动换行(wrap lines)时(在函数调用或函数声明的中间,或多或少,比如,虽然有一些例外),如果它们有合理数量的参数并且变量名称较短时,自动换行将是不必要的。长行似乎与长名称有关,避免名称过长有很大帮助。

换句话说,换行是因为你所写的语义(作为一般规则)而不是因为行的长度。如果您发现这会产生太长的行,那么更改名称或语义,可能也会得到一个好结果。

实际上,这与关于函数应该有多长的建议完全相同。没有 “永远不会有超过N行的函数” 这样的规则,但是程序中肯定会存在行数太多,功能过于微弱的函数,而解决方案是改变这个函数边界的位置,而不是执着在行数上。

Mixed Caps

请参阅 https://golang.org/doc/effective_go.html#mixed-caps。即使 Go 中混合大小写的规则打破了其他语言的惯例,也是适用的。例如,未导出的常量写成 maxLength 而不是MaxLength或MAX_LENGTH。

另见当前页面的 Initialisms 一节。

Named Result Parameters

考虑一下 godoc 中会是什么样子。命名结果参数如:

func (n *Node) Parent1() (node *Node)
func (n *Node) Parent2() (node *Node, err error)

将会造成口吃现象(stutter); 最好这样使用:

func (n *Node) Parent1() *Node
func (n *Node) Parent2() (*Node, error)

另一方面,如果函数返回两个或三个相同类型的参数,或者如果从上下文中不清楚返回结果的含义,那么在某些上下文中添加命名可能很有用。但是不要仅仅为了避免在函数内做结果参数的声明(var 或者 :=)而命名结果参数;这以牺牲不必要的 API 冗长性为代价,换取了一个微小的实现简洁性。

func (f *Foo) Location() (float64, float64, error)

不如以下代码清晰:

// Location returns f's latitude and longitude.
// Negative values mean south and west, respectively.
func (f *Foo) Location() (lat, long float64, err error)

如果函数行数较少,那么非命名结果参数是可以的。一旦它是一个中等规模的函数,请明确返回值。推论:仅仅因为它使得能够直接使用预命名返回而命名结果参数是不值得的。文档的清晰度总比在函数中的一行两行更重要。

最后,在某些情况下,您需要命名结果参数,以便在延迟闭包中更改它,这也是可以的。

Naked Returns

请参阅当前页面 Named Result Parameters 一节。

Package Comments

与 godoc 呈现的所有注释一样,包注释必须出现在 package 声明的临近位置,无空行。

// Package math provides basic constants and mathematical functions.
package math
/*
Package template implements data-driven templates for generating textual
output such as HTML.
....
*/
package template

For "package main" comments, other styles of comment are fine after the binary name (and it may be capitalized if it comes first), For example, for a package main in the directory seedgen you could write:

对于 “package main” 注释,在二进制文件名称之后可以使用其他样式的注释(如果它们放在前面,则可以大写),例如,对于你可以编写 seedgen 目录中下的 main 包注释:

// Binary seedgen ...
package main

或是

// Command seedgen ...
package main

或是

// Program seedgen ...
package main

或是

// The seedgen command ...
package main

或是

// The seedgen program ...
package main

或是

// Seedgen ..
package main

以上是相应示例,它们的合理变体也是可以接受的。

请注意,以小写单词开头的句子不属于包注释的可接受选项,因为注释是公开可见的,应该用适当的英语书写,包括将句子的第一个单词的首字母大写。当二进制文件名称是第一个单词时,即使它与命令行调用的拼写不严格匹配,也需要对其进行大写。

有关评论约定的更多信息,请参阅https://golang.org/doc/effective_go.html#commentary。

Package Names

包中名称的所有引用都将使用包名完成,因此您可以从标识符中省略该名称。例如,如果有一个 chubby 包,你不应该定义类型名称为 ChubbyFile ,否则使用者将写为 chubby.ChubbyFile。而是应该命名类型名称为 File,使用时将写为 chubby.File。避免使用无意义的包名称,如 util,common,misc,api,types 和 interfaces。有关更多信息,请参阅http://golang.org/doc/effective_go.html#package-names和 http://blog.golang.org/package-names

Pass Values

不要只是为了节省几个字节就将指针作为函数参数传递。如果一个函数在整个过程中只引用它的参数x作为x,那么这个参数不应该是一个指针。此常见实例包括将指针传递给 string(string)或是指向接口值(*io.Reader)的指针。在这两种情况下,值本身都是固定大小,可以直接传递。这个建议不适用于大型 struct ,甚至不适用于可能生长的小型 struct。

Receiver Names

方法接收者的名称应该反映其身份;通常,其类型的一个或两个字母缩写就足够了(例如“client”的“c”或“cl”)。不要使用通用名称,例如“me”,“this”或“self”,这是面向对象语言的典型标识符,它们更强调方法而不是函数。名称不必像方法论证那样具有描述性,因为它的作用是显而易见的,不起任何记录目的。名称可以非常短,因为它几乎出现在每种类型的每个方法的每一行上;familiarity admits brevity。使用上也要保持一致:如果你在一个方法中叫将接收器命名为“c”,那么在其他方法中不要把它命名为“cl”。

Receiver Type

选择到底是在方法上使用值接收器还是使用指针接收器可能会很困难,尤其是对于 Go 新手程序员。如有疑问,请使用指针接收器,但有时候值接收器是有意义的,通常是出于效率的原因,例如小的不变结构或基本类型的值。以下是一些有用的指导:

  • 如果接收器是 map,func或 chan,则不要使用指向它们的指针。如果接收器是 slice 并且该方法不重新切片或不重新分配切片,则不要使用指向它的指针。
  • 如果该方法需要改变接收器的值,则接收器必须是指针。
  • 如果接收器是包含 sync.Mutex 或类似同步字段的 struct,则接收器必须是避免复制的指针。
  • 如果接收器是大型结构或数组,则指针接收器更有效。多大才算大?假设它相当于将其包含的所有元素作为参数传递给方法。如果感觉太大,那么对接收器来说也太大了。
  • 函数或方法可以改变接收器吗(并发调用或调用某方法时继续调用相关方法或函数)?在调用方法时,值类型会创建接收器的副本,因此外部更新将不会应用于此接收器。如果必须在原始接收器中看到更改效果,则接收器必须是指针。
  • 如果接收器是 struct,数组或 slice,并且其任何元素是指向可能改变的对象的指针,则更倾向于使用指针接收器,因为它将使读者更清楚地意图。
  • 如果接收器是一个小型数组或 struct,那么它自然是一个值类型(例如,类似于time.Time类型),对于没有可变字段,没有指针的类型,或者只是一个简单的基本类型,如 int 或 string,值接收器是合适的。值接收器可以减少可以生成的垃圾量;如果将值作为参数传递给值类型方法,则可以使用堆栈上的副本而不需要在堆上进行分配。(编译器试图避免这种分配,但它不能总是成功)因此,在没有进行分析之前,不要选择值接收器类型。
  • 最后,如有疑问,请使用指针接收器。

Synchronous Functions

相比异步函数更倾向于同步函数——直接返回结果的函数,或是在返回之前已完成所有回调或 channel 操作的函数。

同步函数让 goroutine 在调用中本地化,能够更容易地推断其生命周期并避免泄漏和数据竞争。同步函数也更容易测试:调用者可以传递输入并检查输出,而无需轮询或同步。

如果调用者需要更多的并发性,他们可以定义和调用单独的 goroutine 中的函数来轻松实现。但是在调用者端删除不必要的并发性是非常困难的——有时是不可能的。

Useful Test Failures

失败的测试也应该提供有用的消息,说明错误,展示输入内容,实际内容以及预期结果。编写一堆 assertFoo 帮助程序可能很吸引人,但请确保您的帮助程序能产生有用的错误消息。假设调试失败测试的人不是你,也不是你的团队。典型的 Go 失败测试如:

if got != tt.want {
    t.Errorf("Foo(%q) = %d; want %d", tt.in, got, tt.want) // or Fatalf, if test can't test anything more past this point
}

请注意,此处的命令是 实际结果!=预期结果,并且错误消息也使用该命令格式。然而一些测试框架鼓励倒写输出格式,如 预期结果 != 实际结果,“预期结果为 0,实际结果为 x”,等等。但是 Go 没有这样做。

如果这看起来像是打了很多字,你可能想写一个表驱动的测试。

在使用具有不同输入的测试帮助程序时以消除失败测试歧义的另一种常见技术是使用不同的 TestFoo 函数包装每个调用者,而测试名称也根据对应的输入命名:

func TestSingleValue(t *testing.T) { testHelper(t, []int{80}) }
func TestNoValues(t *testing.T)    { testHelper(t, []int{}) }

In any case, the onus is on you to fail with a helpful message to whoever's debugging your code in the future.

在任何情况下,你都有责任向可能会在将来调试你的代码的开发者提供有用的消息。

Variable Names

Go 中的变量名称应该短而不是长。对于范围域中的局部变量尤其如此。例如为 line count 定义 c 变量,为 slice index 定义 i 变量。

基本规则:范围域中,越晚使用的变量,名称必须越具有描述性。对于方法接收器,一个或两个字母就足够了。诸如循环索引和读取器(Reader)之类的公共变量可以是单个字母(i,r)。更多不寻常的事物和全局变量则需要更具描述性的名称。

转载于:https://www.cnblogs.com/treasure716/p/9668554.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go Code Review Comments 译文 的相关文章

  • 线程的同步互斥机制(互斥锁)

    一 线程的同步互斥 临界区 访问共享资源的代码段 临界资源 临界区中被读写的共享资源 即同时只能被一个进程访问的资源 线程之间 如果要进行通信 需要引入同步互斥机制 避免产生竞态 保证任何时候都只有一个线程处理临界资源 二 互斥锁 2 1
  • Java中字符串占位替换、字符串拼接、字符串与Collection互转的方式

    场景 字符串占位替换 1 String format 最原始最基础的方式 使用 来表示占位 后面跟上不同的标识符 用于限定这个占位符的参数类型 由jdk原生提供支持 示例 String badao String format hello s
  • 概率论 各种分布及其期望、方差、分布函数

    概率论 各种分布及其期望 方差 分布函数 0 1 分布 二项分布 X b n p 泊松分布 X pi lambda 均匀分布 X U a b 指数分布 正态 高斯分布 X N
  • php绕过分号(;)和尖括号(<>)转义

    实战中发现可写文件且内容可控 尝试写入phpinfo 发现分号 和尖括号 lt gt 被转义 如 尝试写入 实际得到
  • 虚拟机内Ubuntu如何打开摄像头+解决cheese工具黑屏问题

    一 虚拟机如何打开摄像头 1 安装cheese工具 打开Ubuntu摄像头 一般我们安装好Ubuntu之后 可能需要用到摄像头 那么这时候我们可以执行如下命令 1 打开shell终端 输入命令安装cheese工具 cheese工具就可以打开
  • Unable to negotiate with xxx.xxx.xxx.xxx port xxxxx: no matching key exchange method found

    Unable to negotiate with xxx xxx xxx xxx port xxxxx no matching key exchange method found OpenSSH Legacy Options https w
  • 为知笔记私有化部署

    前言 原来一直买的为知笔记vip 但是随着内容越来越 并且不好整理 同时还不能一键全部导出 最后决定将数据迁移到自己服务器上 为止笔记提供了docker镜像 这也方便了部署 其实吧 从产品层面 可以考虑提供一键导出 这样我可能还会买vip
  • chapter 4 能带理论 energy band

    继承自chapter 3 的自由电子模型 4 1 单电子近似 One electron approximation 列出电子运动的薛定谔方程 E 2
  • Vue3+Vite+Vant报错Uncaught SyntaxError: The requested module ‘/node_modules/.vite/vue.js?v=xxxx

    在使用 Vue3 Vite Vant 搭建移动端项目时报错 Uncaught SyntaxError The requested module node modules vite vue js v xxxx 原因 在开发过程中Vue3的依赖
  • MySQL进阶 -- 存储过程 和 触发器

    目录 存储过程 介绍 存储过程的基本语法 变量 系统变量 用户自定义变量 局部变量 if判断 参数 存储过程 介绍 存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合 可以直接调用这些集合 存储过程 调用存储过程可以简化应用开发人
  • 夯实C++基础之刷题:链表——7 链表求和 两数相加

    久违的我的碎碎念 现在看能一边996上班一边坚持学习的真都是了不起的人 新项目开始每天忙的晕头转向 加班回来累得只想躺平 所以快两个月了总共才写了7题 没有空余时间可以学自己的东西真是一件不太让人开心的事情 但就安慰自己 毕竟刚刚毕业开始工
  • GitChat·前端

    GitChat 作者 韩亦乐 前言 我们都知道 大学几乎是没有 Web 前端课的 以我所在的大学为例 唯一引导我们了解 JavaScript 的也只是 人机界面 和 Web应用开发 选修课 再者 由于这些选修课的课时短 面向的主要群体是大部
  • webpack5教程

    目录 简介 创建webpack项目 webpack核心配置文件config的使用 webpack打包多入口 多出口 如何配置webpack dev server 1 了解webpack dev server 2 安装webpack dev
  • python爬虫出现 json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

    1 运行python爬虫出现如下图所示bug 2 解决办法 跟更新下最新的网站请求头request headers 和检查下请求链接是否还是一样 requests url 应该是就长时间没登陆 要跟新最新的cookies 登陆成功 200
  • Microsoft Office2021下载安装教程(非常详细)从零基础入门到精通,看完这一篇就够了

    软件下载 软件 Office 版本 2021 语言 简体中文 大小 4 57G 系统要求 Win10及以上版本 64位操作系统 硬件要求 CPU 2 0GHz 内存 4G 或更高 下载通道 百度网盘丨64位下载链接 https pan ba
  • lnmp下搭建TP5一些小问题

    1 安装lnmp 不多BB 拿到了新的阿里云ECS主机 一键安装lnmp命令 wget http soft vpser net lnmp lnmp1 5 tar gz cO lnmp1 5 tar gz tar zxf lnmp1 5 ta
  • Zotero搭建笔记

    目录 一 官网下载客户端和浏览器插件Zotero translator 二 客户端登录or注册 三 安装插件 3 1 茉莉花 3 2 Zotfile 3 3 抓取网页文件 知网 知乎 微信等 3 4 翻译器 3 5 提取doi号 sci h
  • 嵌入式 程序中的text段、data段和bss段

    一般情况 一个程序本质上都是由 bss段 data段 text段三个段组成 这是计算机程序设计中重要的基本概念 而且在嵌入式系统的设计中也非常重要 牵涉到嵌入式系统运行时的内存大小分配 存储单元占用空间大小的问题 在采用段式内存管理的架构中
  • Java 获取当前日期时间字符串速度测试2306221507

    Java 获取当前日期时间字符串速度测试2306221507 测试代码 import java text SimpleDateFormat import java time import java time format DateTimeF
  • 微众银行区块链张开翔:数字时代的身份基础设施建设

    6月24日 中钞区块链技术研究院 飞天诚信科技股份有限公司 微众银行等17家单位共同发起成立分布式数字身份产业联盟 DID Alliance 简称DIDA 共建分布式数字身份基础设施 打造可信开放数字新生态 本文系微众银行区块链首席架构师张

随机推荐

  • vaspkit使用_vaspkit.014安装使用说明 -

    vaspkit 0 14 修正版发布 安装下载指南 1 下载网址 http www pudn com downloads221 sourcecode unix linux detail1038949 html 免费的 2 利用xshell将
  • 微信小程序之间的参数传递、获取

    一 获取当前页面参数 js onLoad async function options var pages getCurrentPages 获取加载的页面 var currentPage pages pages length 1 获取当前页
  • 记·Linux挖矿病毒应急响应

    一 前言 朋友说他的机器被用来挖矿了 叫我帮他处理一下 正好锻炼锻炼应急响应能力 二 处置 top查看cup发现占用300 确实是被用来挖矿了 查看异常进程9926的pid端口 发现为空查找不到连接情况 怎么回事 查看全部端口网络连接 发现
  • javaAPI(五):比较器Comparable和Comparator

    前言 java中的对象 正常情况下 只能进行比较 或 不能使用 gt 或 lt 的 但是再开发场景中 我们需要对多个对象进行排序 言外之意 就需要比较对象的大小 如何实现 使用两个接口中的一个 Comparable 自然排序 1 像Stri
  • 区块链架构有哪些?

    本文将整理汇总目前常见的区块链各种架构 通过汇总分析 区块链的架构基本都大同小异 前面详细介绍几个 后面的就不重复介绍了 个人技术公众号 解决方案工程师 欢迎同领域的朋友关注 相互交流 一 区块链原理架构 技术层面 区块链的结构如下图所示
  • python中使用numpy.load()读取npz文件遇到的一个小问题

    import numpy as np np load data npz 报错 OSError Errno 22 Invalid argument 之后发现问题 我将 npz文件下载之后修改了名字 如果代码中指定了特定的文件名 例如 xxx
  • Webservice实践(五)基于CXF的服务端开发

    本节将实践目前最流行的第二种web service 发布和调试框架 CXF Apache CXF 是一个开放源代码框架 提供了用于方便地构建和开发 Web 服务的可靠基础架构 它允许创建高性能和可扩展的服务 您可以将这样的服务部署在 Tom
  • 我的世界如何开直连服务器,我的世界服务器如何连接 连接服务器教程

    我的世界分单人模式和多人模式 在游戏中我们一般是玩单人模式的 可是在偌大的世界中室友你一个人 你是否会觉得寂寞呢 下面小编就来介绍下如何进入多人模式 希望大家喜欢 多人模式服务器可以自己创建 也可以加入他人的服务器 那么怎么加入服务器呢 下
  • Python之列表

    标题 列表 什么是列表 列表的创建 列表的删除 列表的访问 列表的常用方法 append insert extend pop remove clear count index list filter reduce lambda 列表支持的运
  • Tomcat:eclipse首选项中没有tomcat?

    为eclipse添加tomcat插件 近期因为兴趣 找了一个javaweb的纯SSM的项目 但是发现我的eclipse4 7版本的 首选项中竟然没有tomcat 所以在网上找了很多方法 终于找到一个很有用的博客 有俩种方法 方法一 一 下载
  • 【OpenCV学习笔记】【函数学习】四(origin+imageData+cvcopy()函数+CvMemStorage 类型+CvPoint类型)

    1 origin 在使用opencv显示图像时会出现图像倒立的情况 这与IplImage的origin属性有关系 origin为0表示顶左结构 即图像的原点是左上角 如果为1为左下角 一般从硬盘读入的图片或者通过cvCreateImage方
  • 289. 生命游戏(Java)

    题目描述 根据 百度百科 生命游戏 简称为生命 是英国数学家约翰 何顿 康威在 1970 年发明的细胞自动机 给定一个包含 m n 个格子的面板 每一个格子都可以看成是一个细胞 每个细胞都具有一个初始状态 1 即为活细胞 live 或 0
  • Python期末实训,爬虫实验报告

    Python爬取豆瓣电影 版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net qq 45774645 article details 11
  • 华为手机微信聊天记录删除怎么恢复?基于华为电脑助手备份的恢复方法

    华为手机最新的微信记录恢复方法 简单有效 HiSuite是华为手机官方的手机电脑助手管理软件 可以把手机设备上的数据备份至电脑 支持联系人 短信 应用程序等的备份 同样HiSuite也可以把微信库文件完整地备份到电脑上 这样就可以扫描微信库
  • 如何编写REST API

    编写REST API REST API规范 编写REST API 实际上就是编写处理HTTP请求的async函数 不过 REST请求和普通的HTTP请求有几个特殊的地方 REST请求仍然是标准的HTTP请求 但是 除了GET请求外 POST
  • Oracle 动态sql 实现方式

    1 2 Sample Program 10 Dynamic SQL Method 4 3 4 This program connects you to ORACLE using your username and 5 password th
  • 后端接口判断字段必填_ERP系统会计凭证中的那些必填项

    作者 Jelly 声明 本文章仅代表原作者观点 仅用于SAP软件的应用与学习 不代表SAP公司 01 凭证日期 凭证日期是必填的 凭证日期填写原始单据的日期 02 过账日期 过账日期是必填的 凭证正式过账到系统的日期 系统默认凭证记账当日
  • 微信小程序webview(H5页面)调用微信小程序支付

    1 业务描述 微信小程序商城入口进入的页面是商城H5页面 在H5页面进行微信支付如何实现 2 微信小程序 webview访问H5页面 必须使用微信小程序支付 如何实现以及实现方式以及支付后页面返回功能 商品详情 h5页面 gt 商品确认页
  • 人工智能不断发展扫码升级刷脸是必然趋势

    人工智能技术的不断发展 刷码升级成刷脸也是必然趋势 刷脸技术落地以后 迎合5G浪潮 将会提供更精准 更完善 更丰富化的服务 它的全面应用将会为企业带去智能化体验 也会引发新一轮的行业变革 起到真正的赋能作用 支付宝 微信支付 银联的三大巨头
  • Go Code Review Comments 译文

    持续更新中 原文最新链接https github com golang go wiki CodeReviewComments 5a40ba36d388ff1b8b2dd4c1c3fe820b8313152f Github译文链接https