Trinta minutos para começar a usar o Go básico (Java Kid Edition)

Prefácio

Vá definição de idioma

Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态、强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC,结构形态及 CSP-style 并发计算

Âmbito de aplicação

Este artigo é adequado para iniciantes que aprenderam outras linguagens orientadas a objetos (Java, Php), mas não aprenderam a linguagem Go. O artigo explica principalmente os quatro aspectos da sintaxe básica da linguagem Go, programação orientada a objetos, simultaneidade e erros na comparação das funções de Go e Java .

1. Gramática básica

A sintaxe básica da linguagem Go é basicamente semelhante à das linguagens de programação convencionais. A diferença é a forma de declarar variáveis. Os conceitos e funções de arrays, fatias e dicionários não são os mesmos de Java. em Java podem ser usados ​​​​por analogia.

1.1 Variáveis, constantes, valores nulos e zero, métodos, pacotes, visibilidade, ponteiros

1.1.1 Declaração de variáveis

Existem duas maneiras na linguagem Go

1. Use vara declaração de palavra-chave e deve-se observar que, diferentemente da maioria das linguagens fortemente tipadas, o tipo de variável declarado na linguagem Go está localizado após o nome da variável. Não há necessidade de ponto e vírgula no final de uma instrução Go.

var num int

var result string = "this is result"

2. Use :=atribuição.

num := 3Equivalente avar num int = 3

O tipo da variável será correspondido de acordo com o valor no lado direito. Por exemplo, "3" corresponderá a int, "3.0" corresponderá a float64 e "resultado" corresponderá a string.

1.1.2 Declaração constante

Use constpara declarar uma constante. Uma constante não pode ser alterada depois de declarada.

const laugh string = "go"

1.1.3 valor nulo e zero

Declare apenas variáveis ​​não atribuídas, cujo valor seja nulo. Semelhante a " nulo" em java .

Declarações de variáveis ​​sem valores iniciais explícitos recebem seu valor zero .

O valor zero é:

  • O tipo numérico é 0,

  • O tipo booleano é false,

  • String é ""(string vazia).

1.1.4 Métodos e pacotes

Definição de métodos em Go

Use a palavra-chave func para definir um método, seguida pelo nome do método, depois pelos parâmetros e pelo valor de retorno (se houver, se não houver valor de retorno, ele não será escrito).

func MethodName(p1 Parm, p2 Parm) int{}

//学习一个语言应该从Hello World开始!
package main

import "fmt"

func main() {
	fmt.Println("Hello World!")// Hello World!
    fmt.Println(add(3, 5)) //8
    var sum = add(3, 5)
}

func add(a int, b int) int{
    return a+b;
}

Vários valores de retorno

Uma grande diferença entre as funções Go e outras linguagens de programação é que elas suportam vários valores de retorno, o que é muito útil ao lidar com erros de programa. Por exemplo, se a função acima addsuportar apenas a adição de números inteiros não negativos, um erro será relatado se um número negativo for passado.

//返回值只定义了类型 没有定义返回参数
func add(a, b int) (int, error) {
    if a < 0 || b < 0 {
        err := errors.New("只支持非负整数相加")
        return 0, err
    }
    a *= 2
    b *= 3
    return a + b, nil
}

//返回值还定义了参数 这样可以直接return 并且定义的参数可以直接使用 return时只会返回这两个参数
func add1(a, b int) (z int, err error) {
    if a < 0 || b < 0 {
        err := errors.New("只支持非负整数相加")
        return   //实际返回0 err 因为z只定义没有赋值 则nil值为0
    }
    a *= 2
    b *= 3
    z = a + b
    return //返回 z err
}

func main()  {
    x, y := -1, 2
    z, err := add(x, y)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Printf("add(%d, %d) = %d\n", x, y, z)
}

Parâmetros de comprimento variável

func myfunc(numbers ...int) {
    for _, number := range numbers {
        fmt.Println(number)
    }
}

slice := []int{1, 2, 3, 4, 5}
//使用...将slice打碎传入
myfunc(slice...)

Pacotes e Visibilidade

Na linguagem Go, sejam variáveis, funções ou atributos de classe e métodos de membro, sua visibilidade é baseada na dimensão do pacote, em vez da programação tradicional, onde a visibilidade dos atributos de classe e métodos de membro é encapsulada na classe à qual eles pertencem e private, modificam sua visibilidade com essas palavras-chave protectede .public

A linguagem Go não fornece essas palavras-chave, sejam elas variáveis, funções ou atributos e métodos membros de classes personalizadas, sua visibilidade é determinada com base na capitalização de suas primeiras letras . a primeira letra do nome do método , você pode acessar diretamente essas variáveis, propriedades, funções e métodos fora do pacote, caso contrário, eles só podem ser acessados ​​​​dentro do pacote. Portanto, a visibilidade dos atributos da classe da linguagem Go e dos métodos membros está no pacote. nível, e não classe um.

Se domainhouver três arquivos .go em uma pasta nomeada, então os três arquivos packagedeverão estar domainentre eles, o arquivo onde está localizado o método principal de entrada do programa e o pacote.main

//定义了此文件属于 main 包
package main

//通过import导入标注库中包
import "fmt"

func main() {
	fmt.Println("Hello World!")// Hello World!
    fmt.Println(add(3, 5)) //8
    var sum = add(3, 5)
}

func add(a int, b int) int{
    return a+b;
}

1.1.5 Ponteiros

Para aqueles que estudaram a linguagem C, os ponteiros são bastante familiares. O ponteiro que entendo é na verdade um valor de endereço hexadecimal real na memória.

func main() {
    i := 0
    //使用&来传入地址
    fmt.Println(&i) //0xc00000c054
    
    var a, b int = 3 ,4
    //传入 0xc00000a089 0xc00000a090
    fmt.Println(add(&a, &b)) 
}

//使用*来声明一个指针类型的参数与使用指针
func add(a *int, b *int)int{
    //接收到 0xc00000a089 0xc00000a090
    //前往 0xc00000a089位置查找具体数据 并取赋给x
    x := *a
    //前往 0xc00000a090位置查找具体数据 并取赋给y
    y := *b
	return x+y
}

1.2 Condições, loops, ramificações

1.2.1 Condições

Basicamente o mesmo que na linguagem Java

// if
if condition { 
    // do something 
}

// if...else...
if condition { 
    // do something 
} else {
    // do something 
}

// if...else if...else...
if condition1 { 
    // do something 
} else if condition2 {
    // do something else 
} else {
    // catch-all or default 
}

1.2.2 Ciclo

sum := 0 

//普通for循环
for i := 1; i <= 100; i++ { 
    sum += i 
}

//无限循环
for{
    sum++
    if sum = 100{
        break;
    }
}

//带条件的循环
for res := sum+1; sum < 15{
    sum++
    res++
}

//使用kv循环一个map或一个数组  k为索引或键值 v为值 k、v不需要时可以用_带替
for k, v := range a {
    fmt.Println(k, v)
}

1.2.3 Filial

score := 100
switch score {
case 90, 100:
    fmt.Println("Grade: A")
case 80:
    fmt.Println("Grade: B")
case 70:
    fmt.Println("Grade: C")
case 65:
    fmt.Println("Grade: D")
default:
    fmt.Println("Grade: F")
}

1.3 Matrizes, fatias, dicionários

1.3.1 Matriz

A função de array é semelhante à linguagem Java, o comprimento é imutável e arrays multidimensionais podem ser usados, ou valores podem ser armazenados ou obtidos por meio de arrays[i].

//声明
var nums [3]int 
//声明并初始化
var nums = [3]int{1,2,3} <==> nums:=[3]int{1,2,3}

//使用
for sum := 0, i := 0;i<10{
	sum += nums[i]
	i++
}
//修改值
num[0] = -1

Arrays são relativamente simples de usar, mas existe um problema difícil de resolver: comprimento fixo .

Por exemplo, quando precisamos de uma estrutura de dados no programa para armazenar todos os usuários obtidos, porque o número de usuários muda com o tempo, mas o comprimento do array não pode ser alterado, então o array não é adequado para armazenar dados cujo comprimento muda . Portanto, os problemas acima são resolvidos usando fatias na linguagem Go.

1.3.2 Fatiamento

Fatiar é um conceito completamente novo em comparação com Java. Em Java, para estruturas de armazenamento de dados de comprimento variável, você pode usar a interface List para concluir operações, como ArrayList e LinkList. Essas interfaces podem adicionar e obter dados a qualquer momento e não há limite de comprimento. No entanto, não existe tal interface em Go. Em vez disso, o armazenamento de dados de comprimento variável é realizado por meio de fatias .

A maior diferença entre fatias e arrays é que as fatias não precisam declarar o comprimento. Mas as fatias não são independentes das matrizes. Uma matriz pode ser considerada como a matriz subjacente da fatia, e a fatia pode ser considerada uma referência a um fragmento contínuo da matriz. As fatias podem ser criadas usando apenas uma parte de uma matriz ou a matriz inteira, e é ainda possível criar uma fatia maior que a matriz subjacente:

comprimento, capacidade

切片的长度就是它所包含的元素个数。

切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。

切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。

O comprimento da fatia é funcionalmente análogo ao size() de List em Java, ou seja, o comprimento da fatia é percebido por meio de len(slice) e len(slice) pode ser repetido para controlar dinamicamente o conteúdo específico no fatiar. A capacidade de slices não é muito utilizada no desenvolvimento atual, basta entender seu conceito.

Criar fatias

//声明一个数组
var nums =[3]int{1, 2, 3}
//0.直接声明
var slice =[]int{0, 1, 2}

//1.从数组中引用切片 其中a:b是指包括a但不包括b
var slice1 = nums[0:2] //{1,2}
//如果不写的则默认为0(左边)或最大值(右边)
var slice2 = slice1[:2] <==> var slice2 = slice1[0:] <==>var slice2 = slice1[:]

//2.使用make创建Slice 其中int为切片类型,4为其长度,5为容量
slice3 := make([]int, 5)
slice4 := make([]int, 4, 5)

Operação dinâmica de fatias

//使用append向切片中动态的添加元素
func append(s []T, vs ...T) []T

slice5 := make([]int, 4, 5) //{0, 0, 0, 0}
slice5 = append(slice5, 1) //{0,0,0,0,1}

//删除第一个0
sliece5 = slice5[1:]

Cenários comuns para fatiar

Simule o problema mencionado acima usando a solução de fatiamento

//声明切片
var userIds = []int{}
//模拟获取所有用户ID
for i := 0; i< 100{
    userIds = append(userIdS, i);
    i++;
}
//对用户信息进行处理
for k,v := range userIds{
    userIds[k] = v++
}

1.3.3 Dicionário

Dicionário, também conhecido como 'par chave-valor' ou 'valor-chave', é uma estrutura de dados comumente usada. Existem várias interfaces de mapa em Java, e as comumente usadas são HashMap, etc. No Go, os dicionários são usados ​​para armazenar pares de valores-chave. Os dicionários não são ordenados, portanto, a ordem dos dados não é garantida com base na ordem de adição.

Declaração e inicialização do dicionário

//string为键类型,int为值类型
maps := map[string]int{
  "java" : 1,
  "go" : 2,
  "python" : 3,
}

//还可以通过make来创建字典 100为其初始容量 超出可扩容
maps = make(map[string]int, 100)

Cenários de uso de dicionário

//直接使用
fmt.Println(maps["java"]) //1

//赋值
maps["go"] = 4

//取值 同时判断map中是否存在该键 ok为bool型
value, ok := maps["one"] 
if ok { // 找到了
  // 处理找到的value 
}

//删除
delete(testMap, "four")

2. Programação orientada a objetos

2.1 Aulas na linguagem Go

Como todos sabemos, em linguagens orientadas a objetos, uma classe deve ter três estruturas: atributos, construtores e métodos de membros, e a linguagem Go não é exceção.

2.1.1 Declaração e inicialização de classe

Não existe um conceito claro de classe na linguagem Go. Apenas structpalavras-chave podem ser funcionalmente analogizadas a "classes" em linguagens orientadas a objetos. Por exemplo, para definir uma classe de aluno, você pode fazer o seguinte:

type Student struct {
    id int
    name string
    male bool
    score float64
}//定义了一个学生类,属性有id name等,每个属性的类型都在其后面

//定义学生类的构造方法
func NewStudent(id uint, name string, male bool, score float64) *Student {
    return &Student{id, name, male, score}
}

//实例化一个类对象
student := NewStudent(1, "学院君", 100)
fmt.Println(student)

2.1.2 Métodos de membros

A declaração do método membro em Go não é a mesma que em outras linguagens. Tomando a classe Aluno como exemplo,

//在方法名前,添加对应的类,即可认为改方法为该类的成员方法。
func (s Student) GetName() string  {
    return s.name
}

//注意这里的Student是带了*的 这是因为在方法传值过程中 存在着值传递与引用传递 即指针的概念 当使用值传递时 编译器会为该参数创建一个副本传入 因此如果对副本进行修改其实是不生效的 因为在执行完此方法后该副本会被销毁 所以此处应该是用*Student 将要修改的对象指针传入 修改值才能起作用
func (s *Student) SetName(name string) {
    //这里其实是应该使用(*s).name = name,因为对于一个地址来说 其属性是没意义的 不过这样使用也是可以的 因为编译器会帮我们自动转换
    s.name = name
}

2.2 Interface

As interfaces desempenham um papel vital na linguagem Go. Se goroutine e channel são os pilares que suportam o modelo de simultaneidade da linguagem Go, então as interfaces são os pilares de todo o sistema de tipos da linguagem Go . A interface da linguagem Go não é apenas uma interface. Vamos explorar os recursos da interface da linguagem Go passo a passo.

2.2.1 Implementação de interface intrusiva tradicional

Semelhante à implementação de classes, o conceito de interface da linguagem Go é completamente diferente dos conceitos de interface fornecidos em outras linguagens. Tomando Java e PHP como exemplo, as interfaces existem principalmente como contratos entre diferentes classes, e a implementação do contrato é obrigatória. Isso se reflete nos detalhes específicos: se uma classe implementa uma determinada interface, ela deve implementar todos os métodos declarados. , isso é chamado de "cumprimento do contrato":

// 声明一个'iTemplate'接口
interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}


// 实现接口
// 下面的写法是正确的
class Template implements iTemplate
{
    private $vars = array();

    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }

    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }

        return $template;
    }
}

Neste momento, se houver outra interface iTemplate2que declare um iTemplatemétodo de interface exatamente igual a , mesmo com o mesmo nome iTemplate, mas localizado em um namespace diferente, o compilador também pensará que a classe acima Templateapenas implementa iTemplatee não implementa iTemplate2a interface.

Isso é dado como certo em nosso entendimento anterior, seja herança entre classes ou implementação entre classes e interfaces, em linguagens de herança única, como Java e PHP, existe um relacionamento hierárquico estrito. Uma classe só pode herdar diretamente de um. classe pai, e uma classe só pode implementar uma interface especificada. Se não for explicitamente declarada para herdar de uma classe pai ou implementar uma determinada interface, então a classe não tem nada a ver com a classe pai ou a relação de interface.

Chamamos esse tipo de interface de interface intrusiva . A chamada "intrusiva" significa que a classe de implementação deve declarar explicitamente que implementa uma interface. Embora este método de implementação seja bastante claro e simples, ainda existem alguns problemas, especialmente ao projetar a biblioteca padrão, porque a biblioteca padrão deve envolver o design da interface. O demandante da interface é a classe de implementação de negócios, e somente a classe de implementação de negócios pode. ser escrito especificamente. Só então saberemos quais métodos precisam ser definidos. Antes disso, a interface da biblioteca padrão pode ser implementada de acordo com a interface acordada. projetá-lo nós mesmos. O problema aqui é que o design da interface e a implementação do negócio nem sempre podem prever quais funções o lado comercial implementará, o que resulta em uma desconexão entre o design e a implementação.

O design excessivo da interface fará com que algumas classes de implementação de métodos declaradas sejam completamente desnecessárias. Se o design for muito simples, não atenderá às necessidades do negócio. Isso é realmente um problema e não faz sentido discuti-los sem o usuário. cenários de uso. Tomemos como exemplo a interface SessionHandlerInterface que vem com o PHP. Os métodos de interface declarados por esta interface são os seguintes:

SessionHandlerInterface {
    /* 方法 */
    abstract public close ( void ) : bool
    abstract public destroy ( string $session_id ) : bool
    abstract public gc ( int $maxlifetime ) : int
    abstract public open ( string $save_path , string $session_name ) : bool
    abstract public read ( string $session_id ) : string
    abstract public write ( string $session_id , string $session_data ) : bool
}

O gerenciador de sessão definido pelo usuário precisa implementar esta interface, ou seja, deve implementar todos os métodos declarados por esta interface. Porém, ao realmente fazer o desenvolvimento de negócios, alguns métodos não precisam realmente ser implementados. Redis ou Memcached como sessão Quanto às memórias, elas próprias contêm um mecanismo de reciclagem de expiração, portanto gco método não precisa ser implementado. Por exemplo, closeo método não tem sentido para a maioria dos drivers.

É precisamente por causa desse design irracional que você precisa enfrentar os dois problemas a seguir ao escrever cada interface na biblioteca de classes PHP (Java é semelhante):

  1. Quais métodos de interface precisam ser declarados para uma interface?

  2. Se várias classes implementarem o mesmo método de interface, como a interface deverá ser projetada? Por exemplo, o acima SessionHandlerInterface, é necessário dividi-lo em várias interfaces mais subdivididas para se adaptar às necessidades de diferentes classes de implementação?

A seguir, vamos dar uma olhada em como a interface da linguagem Go evita esses problemas.

2.2.2 Implementação da interface da linguagem Go

Na linguagem Go, a implementação de uma interface por uma classe é igual à herança de uma subclasse de uma classe pai. Não existe implementuma palavra-chave como esta para declarar explicitamente qual interface a classe implementa . métodos exigidos por uma interface, dizemos que esta classe implementa a interface .

Por exemplo, definimos uma classe e Fileimplementamos Read()quatro métodos:Write()Seek()Close()

type File struct { 
    // ...
}

func (f *File) Read(buf []byte) (n int, err error) 
func (f *File) Write(buf []byte) (n int, err error) 
func (f *File) Seek(off int64, whence int) (pos int64, err error) 
func (f *File) Close() error

Suponha que temos a seguinte interface (a linguagem Go usa a palavra-chave para interfacedeclarar a interface para mostrar a diferença do tipo de estrutura, e as chaves contêm o conjunto de métodos a serem implementados):

type IFile interface { 
    Read(buf []byte) (n int, err error) 
    Write(buf []byte) (n int, err error) 
    Seek(off int64, whence int) (pos int64, err error) 
    Close() error 
}

type IReader interface { 
    Read(buf []byte) (n int, err error) 
}

type IWriter interface { 
    Write(buf []byte) (n int, err error) 
}

type ICloser interface { 
    Close() error 
}

Embora Filea classe não implemente explicitamente essas interfaces, ou mesmo saiba da existência dessas interfaces, dizemos que Filea classe implementa essas interfaces porque Filea classe implementa os métodos declarados por todas as interfaces acima. Quando o conjunto de métodos membros de uma classe contém todos os métodos declarados por uma interface, ou seja, se o conjunto de métodos de uma interface é um subconjunto do conjunto de métodos membros de uma determinada classe, consideramos a classe para implementar a interface.

Em comparação com Java e PHP, chamamos essa interface da linguagem Go de interface não intrusiva , porque o relacionamento de implementação entre uma classe e uma interface não é declarado explicitamente, mas é julgado pelo sistema com base no conjunto de métodos dos dois. Isso tem dois benefícios:

  • Primeiro, a biblioteca padrão da linguagem Go não precisa desenhar o diagrama de árvore de herança/implementação da biblioteca de classes. Na linguagem Go, a árvore de herança da classe não tem sentido. o que cada método faz será suficiente.

  • Em segundo lugar, ao definir uma interface, você só precisa se preocupar com quais métodos deve fornecer. Você não precisa mais se preocupar com o quão detalhada a interface precisa ser. Não há necessidade de introduzir o pacote onde a interface está localizada. implementar uma interface. A interface é determinada pelo usuário, sem necessidade de projetar antecipadamente e sem considerar se outros módulos definiram interfaces semelhantes antes.

Desta forma, os problemas de design de interface na programação orientada a objetos tradicional são perfeitamente evitados.

3. Simultaneidade e multithreading

3.1 Gorotina

Para qualquer linguagem excelente, a capacidade de lidar com processamento simultâneo é a chave para determinar seus méritos. Na linguagem Go, o processamento simultâneo é implementado por meio do Goroutine.

func say(s string) {
	fmt.Println(s)
}

func main() {
    //通过 go 关键字新开一个协程
	go say("world")
	say("hello")
}

A linguagem Go não possui tantos bloqueios quanto Java para limitar o acesso simultâneo aos recursos e fornece Mutex apenas para operações de sincronização.

//给类SafeCounter添加锁
type SafeCounter struct {
	v   map[string]int
	mux sync.Mutex
}

// Inc 增加给定 key 的计数器的值。
func (c *SafeCounter) Inc(key string) {
    //给该对象上锁
	c.mux.Lock()
	// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
	c.v[key]++
    //解锁
	c.mux.Unlock()
}

3.2 Canal

A comunicação entre várias corrotinas é feita por meio de Canal, que pode ser funcionalmente análogo à palavra-chave volátil do Java.

ch := make(chan int)chDeclare um canal do tipo int e os dados int poderão ser comunicados entre duas corrotinas .

A transmissão de dados é realizada através do Canal.

ch <- v    // 将 v 发送至信道 ch。
v := <-ch  // 从 ch 接收值并赋予 v。
package main

import "fmt"

func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum // 将和送入 c
}

//对于main方法来说 相当于就是开启了一个协程
func main() {
	s := []int{7, 2, 8, -9, 4, 0}

	c := make(chan int)
    //通过go关键字开启两个协程 将chaneel当做参数传入
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
    //通过箭头方向获取或传入信息
	x, y := <-c, <-c // 从 c 中接收

	fmt.Println(x, y, x+y)
}

4. Tratamento de erros

Erro 4.1

O mecanismo de tratamento de erros da linguagem Go é muito simples e claro. Não há necessidade de aprender conceitos, funções e tipos complexos. A linguagem Go define um padrão para tratamento de erros, ou seja, errora definição da interface é muito simples. :

type error interface { 
    Error() string 
}

Apenas um Error()método é declarado, que retorna uma mensagem de erro do tipo string. Para a maioria das funções ou métodos de classe, se você quiser retornar um erro, você pode basicamente defini-lo como o seguinte padrão - retornar o tipo de erro como o segundo parâmetro:

func Foo(param int) (n int, err error) { 
    // ...
}

Então, ao chamar a função/método que retorna informações de erro, basta escrever o código de processamento de acordo com o seguinte modelo "Declaração Wei Shu":

n, err := Foo(0)

if err != nil { 
    // 错误处理 
} else{
    // 使用返回值 n 
}

Muito simples e elegante.

4.2 adiar

defer é usado para garantir que após a execução de um método, as instruções em defer serão executadas independentemente de o resultado da execução ser bem-sucedido ou não. Semelhante ao uso try..catch..finalmente em Java. Por exemplo, no processamento de arquivos, o fluxo de arquivos deve ser fechado independentemente de o resultado ser bem-sucedido ou não.

func ReadFile(filename string) ([]byte, error) {
    f, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    //无论结果如何 都要关闭文件流
    defer f.Close()

    var n int64 = bytes.MinRead

    if fi, err := f.Stat(); err == nil {
        if size := fi.Size() + bytes.MinRead; size > n {
            n = size
        }
    }
    return readAll(f, n)
}

4.3 pânico

Não existem muitas classes de exceção na linguagem Go. Ao contrário do Java, existem tipos de erro como Error e Exception. É claro que não existem instruções try..catch.

Pânico significa que ocorre um erro durante a operação do programa. Se o erro não for detectado, o sistema travará e sairá. Por exemplo, um simples pânico: a := 1/0.

Isso causará pânico: número inteiro dividido por zero.

imagem.png

A primeira linha indica a rotina com o problema, a segunda linha é o pacote e a função onde o código do problema está localizado, a terceira linha é a localização específica do código do problema e a última linha é o status de saída do programa. informações podem ajudá-lo a localizar rapidamente o problema e resolvê-lo.

4.4 recuperar

Quando há um erro previsível e você não deseja que o programa trave e saia, você pode usar a instrução recuperar() para capturar o pânico não tratado. recuperar deve ser colocado na instrução defer, e a instrução deve estar na frente do método para evitar que o sistema saia de forma anormal se a instrução defer não puder ser executada.

package main

import (
    "fmt"
)

func divide() {
    //通过defer,确保该方法只要执行完毕都要执行该匿名方法
    defer func() {
        //进行异常捕获
        if err := recover(); err != nil {
            fmt.Printf("Runtime panic caught: %v\n", err)
        }
    }()

    var i = 1
    var j = 0
    k := i / j
    fmt.Printf("%d / %d = %d\n", i, j, k)
}

func main() {
    divide()
    fmt.Println("divide 方法调用完毕,回到 main 函数")
}

imagem.png

Pode-se observar que embora ocorra uma exceção, após usarmos retrieve() para capturá-la, o sistema não irá travar e sair, apenas encerrará o método. A fmt.Printf("%d / %d = %d\n", i, j, k)instrução não foi executada porque ocorreu uma exceção quando o código foi executado na etapa anterior, fazendo com que o método terminasse mais cedo.
4 recuperar

Quando há um erro previsível e você não deseja que o programa trave e saia, você pode usar a instrução recuperar() para capturar o pânico não tratado. recuperar deve ser colocado na instrução defer, e a instrução deve estar na frente do método para evitar que o sistema saia de forma anormal se a instrução defer não puder ser executada.

package main

import (
    "fmt"
)

func divide() {
    //通过defer,确保该方法只要执行完毕都要执行该匿名方法
    defer func() {
        //进行异常捕获
        if err := recover(); err != nil {
            fmt.Printf("Runtime panic caught: %v\n", err)
        }
    }()

    var i = 1
    var j = 0
    k := i / j
    fmt.Printf("%d / %d = %d\n", i, j, k)
}

func main() {
    divide()
    fmt.Println("divide 方法调用完毕,回到 main 函数")
}

Pode-se observar que embora ocorra uma exceção, após usarmos retrieve() para capturá-la, o sistema não irá travar e sair, apenas encerrará o método. A fmt.Printf("%d / %d = %d\n", i, j, k)instrução não foi executada porque ocorreu uma exceção quando o código foi executado na etapa anterior, fazendo com que o método terminasse mais cedo.

5. Resumo

Através do estudo acima, você pode inicialmente entender a sintaxe básica do go para fins de uso, mas este artigo por si só não é suficiente para aprender o go. Por exemplo, uma das maiores vantagens do go, a "co-rotina", não é detalhada devido ao objetivo do artigo. Os alunos interessados ​​podem continuar aprendendo.

Decidi desistir do código aberto Hongmeng Wang Chenglu, o pai do código aberto Hongmeng: Hongmeng de código aberto é o único evento de software industrial de inovação arquitetônica na área de software básico na China - o OGG 1.0 é lançado, a Huawei contribui com todo o código-fonte. Google Reader é morto pela "montanha de merda de código" Fedora Linux 40 é lançado oficialmente Ex-desenvolvedor da Microsoft: o desempenho do Windows 11 é "ridiculamente ruim" Ma Huateng e Zhou Hongyi apertam as mãos para "eliminar rancores" Empresas de jogos conhecidas emitiram novos regulamentos : os presentes de casamento dos funcionários não devem exceder 100.000 yuans Ubuntu 24.04 LTS lançado oficialmente Pinduoduo foi condenado por concorrência desleal Compensação de 5 milhões de yuans
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4090830/blog/11054982
Recomendado
Clasificación