20个Go编程最佳实践

鸟窝聊技术 发表于 1年以前  | 总阅读数:608 次

在本教程中,我们将探讨 Golang 中的前 20 个最佳编码实践。这将帮助你编写有效的 Go 代码。

#20: 使用适当的缩进

良好的缩进使你的代码易读。一致地使用制表符或空格(最好是制表符),并遵循 Go 的缩进标准。

package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Println("Hello, World!")
    }
}

运行gofmt以根据 Go 标准自动格式化(缩进)你的代码。

$ gofmt -w your_file.go

#19: 正确导入包

仅导入你需要的包,并格式化导入部分以将标准库包、第三方包和你自己的包分组。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

#18: 使用描述性的变量和函数名

  1. 有意义的名称:使用传达变量目的的名称。
  2. 驼峰命名法:以小写字母开头,并在名称中的每个后续单词的首字母大写。
  3. 短名称:对于生命周期短、范围小的变量,可以使用简洁的名称。
  4. 不要使用缩写:避免使用难以理解的缩写和首字母缩写,而使用描述性名称。
  5. 一致性:在整个代码库中保持命名一致性。
package main

import "fmt"

func main() {
    // 使用有意义的名称声明变量
    userName := "John Doe"   // 驼峰命名法:以小写字母开头,并在名称中的每个后续单词的首字母大写。
    itemCount := 10         // 短名称:短小而简洁,适用于生命周期短、范围小的变量。
    isReady := true         // 不使用缩写:避免使用缩写。

    // 显示变量值
    fmt.Println("User Name:", userName)
    fmt.Println("Item Count:", itemCount)
    fmt.Println("Is Ready:", isReady)
}

// 对于包级别的变量使用mixedCase
var exportedVariable int = 42

// 函数名应该具有描述性
func calculateSumOfNumbers(a, b int) int {
    return a + b
}

// 保持代码库中的命名一致性。

#17: 限制行长度

尽可能保持代码行长度在 80 个字符以下,以提高可读性。

package main

import (
    "fmt"
    "math"
)

func main() {
    result := calculateHypotenuse(3, 4)
    fmt.Println("Hypotenuse:", result)
}

func calculateHypotenuse(a, b float64) float64 {
    return math.Sqrt(a*a + b*b)
}

#16: 使用常量代替魔术值

避免在代码中使用魔术值,即散布在代码中的硬编码数字或字符串,缺乏上下文,使其难以理解目的。为其定义常量,以使代码更易维护。

package main

import "fmt"

const (
    // 定义最大重试次数的常量
    MaxRetries = 3

    // 定义默认超时时间(秒)的常量
    DefaultTimeout = 30
)

func main() {
    retries := 0
    timeout := DefaultTimeout

    for retries < MaxRetries {
        fmt.Printf("Attempting operation (Retry %d) with timeout: %d seconds\n", retries+1, timeout)

        // ... 在此处添加你的代码逻辑 ...

        retries++
    }
}

#15: 错误处理

Go 鼓励开发者显式处理错误,有以下原因:

  • 安全性:错误处理确保意外问题不会导致程序突然崩溃。
  • 清晰性:显式的错误处理使代码更易读,有助于确定错误可能发生的位置。
  • 调试:处理错误为调试和故障排除提供了有价值的信息。

让我们创建一个简单的程序,它读取一个文件并正确处理错误:

package main

import (
    "fmt"
    "os"
)

func main() {
    // 打开一个文件
    file, err := os.Open("example.txt")
    if err != nil {
        // 处理错误
        fmt.Println("Error opening the file:", err)
        return
    }
    defer file.Close() // 当完成时关闭文件

    // 从文件中读取
    buffer := make([]byte, 1024)
    _, err = file.Read(buffer)
    if err != nil {
        // 处理错误
        fmt.Println("Error reading the file:", err)
        return
    }

    // 打印文件内容
    fmt.Println("File content:", string(buffer))
}

#14: 避免使用全局变量

最小化使用全局变量。全局变量可能导致不可预测的行为,使调试变得困难,并阻碍代码重用。它们还可能在程序的不同部分之间引入不必要的依赖关系。相反,通过函数参数和返回值传递数据。

让我们编写一个简单的 Go 程序来说明避免使用全局变量的概念:

package main

import (
    "fmt"
)

func main() {
    // 在main函数中声明并初始化变量
    message := "Hello, Go!"

    // 调用使用局部变量的函数
    printMessage(message)
}

// printMessage是一个带参数的函数
func printMessage(msg string) {
    fmt.Println(msg)
}

#13: 使用结构体处理复杂数据

使用结构体将相关的数据字段和方法组合在一起。它们允许你将相关变量组合在一起,使你的代码更有组织性和可读性。

以下是一个完整的演示在 Go 中使用结构体的程序:

package main

import (
    "fmt"
)

// 定义一个名为Person的结构体,表示一个人的信息。
type Person struct {
    FirstName string // 人的名字
    LastName  string // 人的姓氏
    Age       int    // 人的年龄
}

func main() {
    // 创建一个Person结构体的实例并初始化其字段。
    person := Person{
        FirstName: "John",
        LastName:  "Doe",
        Age:       30,
    }

    // 访问并打印结构体字段的值。
    fmt.Println("First Name:", person.FirstName) // 打印名字
    fmt.Println("Last Name:", person.LastName)   // 打印姓氏
    fmt.Println("Age:", person.Age)             // 打印年龄
}

#12: 为你的代码添加注释

添加注释以解释代码的功能,特别是对于复杂或不明显的部分。

单行注释单行注释以//开头。用于解释特定行的代码。

package main

import "fmt"

func main() {
    // 这是一条单行注释
    fmt.Println("Hello, World!") // 打印问候语
}

多行注释多行注释在/* */中。用于较长的解释或跨多行的注释。

package main

import "fmt"

func main() {
    /*
        这是一条多行注释。
        它可以跨越多行。
    */
    fmt.Println("Hello, World!") // 打印问候语
}

函数注释为函数添加注释,明确其用途、参数和返回值。使用 godoc 风格的函数注释可以使代码更易读。

package main

import "fmt"

// greetUser 通过用户名向用户表示问候。
// 参数:
//   name (string): 要问候的用户的名字。
// 返回:
//   string: 问候消息。
func greetUser(name string) string {
    return "Hello, " + name + "!"
}

func main() {
    userName := "Alice"
    greeting := greetUser(userName)
    fmt.Println(greeting)
}

包注释在 Go 文件的顶部添加注释,描述包的用途。使用相同的 godoc 风格。

package main

import "fmt"

// 这是我们 Go 程序的主要包。
// 它包含入口点(main)函数。
func main() {
    fmt.Println("Hello, World!")
}

#11: 使用 goroutines 进行并发操作

高效地利用 goroutine 进行并发操作。goroutine 是 Go 中轻量级的、并发的执行线程。它们使您能够在没有传统线程开销的情况下并发运行函数。这使您能够编写高度并发和高效的程序。

让我们通过一个简单的例子来演示:

package main

import (
    "fmt"
    "time"
)

// 并发运行的函数
func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Printf("%d ", i)
        time.Sleep(100 * time.Millisecond)
    }
}

// 运行在主 goroutine 中的函数
func main() {
    // 启动 goroutine
    go printNumbers()

    // 继续执行主函数
    for i := 0; i < 2; i++ {
        fmt.Println("Hello")
        time.Sleep(200 * time.Millisecond)
    }
    // 在退出之前确保 goroutine 完成
    time.Sleep(1 * time.Second)
}

#10: 使用 Recover 处理 panic

使用 recover 函数优雅的处理 panic,并防止程序崩溃。在 Go 中,panic 是意外的运行时错误,可能导致程序崩溃。然而,Go 提供了一种称为 recover 的机制来优雅的处理 panic

让我们通过一个简单的例子来演示:

package main

import "fmt"

// 可能会 panic 的函数
func riskyOperation() {
    defer func() {
        if r := recover(); r != nil {
            // 从 panic 中恢复并 gracefully 处理它
            fmt.Println("Recovered from panic:", r)
        }
    }()

    // 模拟 panic 条件
    panic("Oops! Something went wrong.")
}

func main() {
    fmt.Println("Start of the program.")

    // 在一个能从 panic 中恢复的函数中调用 riskyOperation
    riskyOperation()

    fmt.Println("End of the program.")
}

#9: 避免使用 init 函数

避免使用 init 函数,除非必要,因为它可能使代码更难理解和维护。

一个更好的方法是将初始化逻辑移到常规函数中,您可以从主函数中显式调用它,通常更易于控制,增强代码的可读性,并简化测试。

以下是演示避免使用 init 函数的简单 Go 程序:

package main

import (
    "fmt"
)

// InitializeConfig 初始化配置。
func InitializeConfig() {
    // 在这里初始化配置参数。
    fmt.Println("Initializing configuration...")
}

// InitializeDatabase 初始化数据库连接。
func InitializeDatabase() {
    // 在这里初始化数据库连接。
    fmt.Println("Initializing database...")
}

func main() {
    // 显式调用初始化函数。
    InitializeConfig()
    InitializeDatabase()

    // 主程序逻辑在这里。
    fmt.Println("Main program logic...")
}

#8: 使用 defer 进行资源清理

defer 允许你延迟执行函数,直到包围它的函数返回。它通常用于执行诸如关闭文件、解锁互斥锁或释放其他资源等任务。

这确保即使在出现错误的情况下,清理操作也会被执行。

让我们创建一个简单的程序,从文件中读取数据,并使用 defer 确保文件在发生任何错误时都能正确关闭:

package main

import (
 "fmt"
 "os"
)

func main() {
 // 打开文件(将 "example.txt" 替换为你的文件名)
 file, err := os.Open("example.txt")
 if err != nil {
  fmt.Println("Error opening the file:", err)
  return // 出现错误时退出程序
 }
 defer file.Close() // 确保函数退出时文件被关闭

 // 读取并打印文件的内容
 data := make([]byte, 100)
 n, err := file.Read(data)
 if err != nil {
  fmt.Println("Error reading the file:", err)
  return // 出现错误时退出程序
 }

 fmt.Printf("Read %d bytes: %s\n", n, data[:n])
}

#7: 推荐使用复合字面值而非构造函数

使用复合字面值来创建结构体的实例,而不是使用构造函数。

为什么使用复合字面值?复合字面值提供了几个优势:

  • 简洁性
  • 可读性
  • 灵活性

让我们通过一个简单的例子来演示:

package main

import (
 "fmt"
)

// 定义一个表示个人信息的结构体类型
type Person struct {
 FirstName string // 个人的名字
 LastName  string // 个人的姓氏
 Age       int    // 个人的年龄
}

func main() {
 // 使用复合字面值创建一个 Person 实例
 person := Person{
  FirstName: "John", // 初始化 FirstName 字段
  LastName:  "Doe",  // 初始化 LastName 字段
  Age:       30,     // 初始化 Age 字段
 }

 // 打印个人信息
 fmt.Println("个人详情:")
 fmt.Println("名字:", person.FirstName) // 访问并打印名字字段
 fmt.Println("姓氏:", person.LastName)  // 访问并打印姓氏字段
 fmt.Println("年龄:", person.Age)        // 访问并打印年龄字段
}

#6: 减少函数参数

在 Go 中,编写干净高效的代码是至关重要的。其中一种方法是减少函数参数的数量,这可以导致更易维护和可读的代码。

让我们通过一个简单的例子来探讨这个概念:

package main

import "fmt"

// Option 结构体用于保存配置选项
type Option struct {
    Port    int
    Timeout int
}

// ServerConfig 是一个接受 Option 结构体的函数
func ServerConfig(opt Option) {
    fmt.Printf("服务器配置 - 端口:%d,超时:%d 秒\n", opt.Port, opt.Timeout)
}

func main() {
    // 创建一个具有默认值的 Option 结构体
    defaultConfig := Option{
        Port:    8080,
        Timeout: 30,
    }

    // 使用默认选项配置服务器
    ServerConfig(defaultConfig)

    // 使用新的 Option 结构体修改端口
    customConfig := Option{
        Port: 9090,
    }

    // 使用自定义端口值和默认超时配置服务器
    ServerConfig(customConfig)
}

在这个例子中,我们定义了一个 Option 结构体,用于保存服务器的配置参数。与将多个参数传递给ServerConfig函数不同,我们使用一个单独的Option结构体,使得代码更易于维护和扩展。这种方法在处理具有大量配置参数的函数时特别有用。

#5: 使用显式返回值而不是具名返回值以提高清晰度

在 Go 中,通常使用具名返回值,但它们有时会使代码不够清晰,尤其是在较大的代码库中。

让我们通过一个简单的例子来看看它们之间的区别。

package main

import "fmt"

// namedReturn 演示具名返回值。
func namedReturn(x, y int) (result int) {
    result = x + y
    return
}

// explicitReturn 演示显式返回值。
func explicitReturn(x, y int) int {
    return x + y
}

func main() {
    // 具名返回值
    sum1 := namedReturn(3, 5)
    fmt.Println("具名返回值:", sum1)

    // 显式返回值
    sum2 := explicitReturn(3, 5)
    fmt.Println("显式返回值:", sum2)
}

在上面的示例程序中,我们有两个函数,namedReturnexplicitReturn。它们的区别如下:

namedReturn 使用了具名返回值 result。虽然清楚函数返回的是什么,但在更复杂的函数中可能不够直观。explicitReturn 直接返回结果。这更简单、更明确。

#4: 保持函数复杂性最小化

函数复杂性指的是函数代码中的错综复杂度、嵌套和分支程度。保持函数复杂性的低水平使得你的代码更易读、更易维护,且更不容易出错。

让我们通过一个简单的例子来探讨这个概念:

package main

import (
 "fmt"
)

// CalculateSum 返回两个数字的和。
func CalculateSum(a, b int) int {
 return a + b
}

// PrintSum 打印两个数字的和。
func PrintSum() {
 x := 5
 y := 3
 sum := CalculateSum(x, y)
 fmt.Printf("%d 和 %d 的和是 %d\n", x, y, sum)
}

func main() {
 // 调用 PrintSum 函数来演示最小函数复杂性。
 PrintSum()
}

在上面的示例程序中:

  1. 我们定义了两个函数,CalculateSumPrintSum,各自负责特定的任务。
  2. CalculateSum 是一个简单的函数,用于计算两个数字的和。
  3. PrintSum 利用 CalculateSum 计算并打印出 53 的和。
  4. 通过保持函数简洁并专注于单一任务,我们保持了较低的函数复杂性,提高了代码的可读性和可维护性。

#3: 避免变量的屏蔽

变量的屏蔽(shadowing)发生在在更小的作用域内声明了一个同名的新变量,这可能导致意外的行为。它隐藏了同名的外部变量,在该作用域内无法访问。避免在嵌套作用域内屏蔽变量,以防止混淆。

让我们看一个示例程序:

package main

import "fmt"

func main() {
    // 声明并初始化一个外部变量 'x',其值为 10。
    x := 10
    fmt.Println("外部 x:", x)

    // 进入一个内部作用域,其中新变量 'x' 屏蔽了外部的 'x'。
    if true {
        x := 5 // 屏蔽发生在这里
        fmt.Println("内部 x:", x) // 打印内部的 'x',其值为 5。
    }

    // 外部的 'x' 保持不变且仍然可访问。
    fmt.Println("内部作用域后的外部 x:", x) // 打印外部的 'x',其值为 10。
}

#2: 使用接口进行抽象

抽象抽象是 Go 语言中的一个基本概念,允许我们定义行为而不指定实现细节。

接口在 Go 中,接口是一组方法签名。

在泛型功能增加后,接口的是一组方法签名和类型约束,也就是一组类型的集合。不过这里介绍的还是原始的接口功能,所以上面的描述也每问题。

任何实现接口所有方法的类型都会隐式满足该接口。

这使我们能够编写能够与不同类型一起工作的代码,只要它们遵循相同的接口。

下面是 Go 中的一个示例程序,演示了使用接口进行抽象的概念:

package main

import (
    "fmt"
    "math"
)

// 定义 Shape 接口
type Shape interface {
    Area() float64
}

// 矩形结构体
type Rectangle struct {
    Width  float64
    Height float64
}

// 圆形结构体
type Circle struct {
    Radius float64
}

// 为矩形实现 Area 方法
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// 为圆形实现 Area 方法
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

// 打印任意 Shape 的面积的函数
func PrintArea(s Shape) {
    fmt.Printf("面积: %.2f\n", s.Area())
}

func main() {
    rectangle := Rectangle{Width: 5, Height: 3}
    circle := Circle{Radius: 2.5}

    // 在矩形和圆形上调用 PrintArea,它们都实现了 Shape 接口
    PrintArea(rectangle) // 打印矩形的面积
    PrintArea(circle)    // 打印圆形的面积
}

在这个单一的程序中,我们定义了 Shape 接口,创建了两个结构体 RectangleCircle,它们都实现了 Area() 方法,并使用 PrintArea 函数来打印满足 Shape 接口的任何形状的面积。

这演示了在 Go 中如何使用接口进行抽象,以使用一个共同的接口处理不同类型。

#1: 避免混淆库包和可执行文件

在 Go 语言中,保持库包和可执行文件之间清晰的分离是至关重要的,以确保代码清晰和可维护。

以下是演示库和可执行文件分离的示例项目结构:

myproject/
    ├── main.go
    ├── myutils/
       └── myutils.go

myutils/myutils.go:

package myutils

import "fmt"

// 导出的打印消息的函数
func PrintMessage(message string) {
    fmt.Println("来自 myutils 的消息:", message)
}

main.go:

package main

import (
    "fmt"
    "myproject/myutils" // 导入自定义包
)

func main() {
    message := "你好,Golang!"

    // 调用自定义包 myutils 中的导出函数
    myutils.PrintMessage(message)

    // 演示主程序逻辑
    fmt.Println("来自 main 的消息:", message)
}

在上面的示例中,我们有两个独立的文件:myutils.gomain.gomyutils.go 定义了一个名为 myutils 的自定义包。它包含一个打印消息的导出函数 PrintMessagemain.go 是可执行文件,使用相对路径("myproject/myutils")导入了自定义包 myutilsmain.go 中的 main 函数调用 myutils 包中的 PrintMessage 函数并打印一条消息。这种关注点分离使代码保持有序和可维护。

参考资料

  • [1] Golang Best Practices (Top 20): https://medium.com/@golangda/golang-quick-reference-top-20-best-coding-practices-c0cea6a43f20

本文由微信公众号鸟窝聊技术原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/maH0cibncPNxALYi1QMRVA

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 目录