Go语言之结构体

news2024/11/24 19:41:49

在实际开发中,我们可以将一组类型不同的、但是用来描述同一件事物的变量放到结构体中。例如,在校学生有姓名、年龄、身高、成绩等属性,学了结构体后,我们就不需要再定义多个变量了,将它们都放到结构体中即可。

在Go语言中,结构体承担着面向对象语言中类的作用。Go语言中,结构体本身仅用来定义属性。还可以通过接收器函数来定义方法,使用内嵌结构体来定义继承。这样使用结构体相关操作Go语言就可以实现OOP面向对象编程了。

1、声明结构体

Go语言通过type和struct关键字声明结构体,格式如下:

type 类型名 struct {   // 标识结构体的类型名,在同一个包内不能重复
    字段1 字段1类型    // 字段名必须唯一
    字段2 字段2类型
    …
}

Go语言结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由 int、char、float 等基本类型组成的。你可以认为结构体是一种聚合类型。


type Student struct {
    sid    int
    name   string
    age    int8
    course []string //  选秀课程
}

Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性。结构体成员,也可称之为成员变量,字段,属性。属性要满足唯一性。
同类型的变量也可以写在一行,用逗号隔开

type Book struct {
   title,author string
   price int
}

2、结构体的实例化

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存,因此必须在定义结构体并实例化后才能使用结构体的字段。实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。
实例化方式包括如下几种。

2.1、声明结构体变量再赋值

结构体本身是一种类型,可以像整型、字符串等类型一样,以 var 的方式声明结构体即可完成实例化。

package main

import "fmt"

type Student struct {
    sid    int
    name   string
    age    int8
    course []string //  选秀课程
}

func main() {

    // 声明一个结构体对象 ,值类型,默认开辟空间,字段赋予零值
    var s Student
    fmt.Println("s:", s)
    // 要访问结构体成员,需要使用点号 . 操作符
    fmt.Println(s.name)
    // 更改成员变量的值
    s.name = "yuan"
    fmt.Println(s.name)
    // s.course[0] = "chinese"   // 结果,如何调整

}

1、结构体属于值类型,即var声明后会像整形字符串一样创建内存空间。
2、创建结构体对象如果没有给字段赋值,则默认零值(字符串默认 “",数值默认0,布尔默认false,切片和map默认nil对象)

结构体的内存存储:

package main

import "fmt"

type Student struct {
    sid    int
    name   string
    age    int8
    course []string //  选秀课程
}

func main() {

    // 声明一个结构体对象 ,值类型,默认开辟空间,字段赋予零值
    var s Student
    fmt.Println("s:", s)
    s.sid = 1001
    s.name = "yuan"
    s.age = 23
    s.course = []string{"chinese", "math", "english"}
    fmt.Printf("%p\n", &s)
    fmt.Printf("%p\n", &(s.sid))
    fmt.Printf("%p\n", &(s.name))
    fmt.Printf("%p\n", &(s.age))
    fmt.Printf("%p\n", &(s.course)) // 切片24个字节
}

在这里插入图片描述

之前我们学习过值类型和引用类型,知道值类型是变量对应的地址直接存储值,而引用类型是变量对应地址存储的是地址。因为结构体因为是值类型,所以p的地址与存储的第一个值的地址是相同的,而后面每一个成员变量的地址是连续的。

2.2、实例化之 结构体

// (1) 方式1
s1 := Student{}
s1.sid = 1001
s1.name = "yuan"
// (2) 方式2:键值对赋值
s2 := Student{sid: 1002, name: "rain", course: []string{"chinese", "math", "english"}}
fmt.Println(s2)
// (3) 方式3:多值赋值
s3 := Student{1003, "alvin", 22, []string{"chinese", "math", "english"}}
fmt.Println(s3)

1、结构体可以使用“键值对”(Key value pair)初始化字段,每个“键”(Key)对应结构体中的一个字段,键的“值”(Value)对应字段需要初始化的值。键值对的填充是可选的,不需要初始化的字段可以不填入初始化列表中,走默认值。
2、多值初始化方式必须初始化结构体的所有字段且每一个初始值的填充顺序必须与字段在结构体中的声明顺序一致。
3、键值对与值列表的初始化形式不能混用。

2.3、实例化之&结构体

package main

import "fmt"

type Student struct {
    sid    int
    name   string
    age    int8
    course []string //  选秀课程
}

func CourseInit(stu Student) {
    stu.course = []string{"chinese", "math", "english"}
    fmt.Println(stu)
}

func CourseInit2(stu *Student) {
    (*stu).course = []string{"chinese", "math", "english"}
}

func main() {

    // 案例1
    s1 := Student{sid: 1001, name: "alvin", age: 32}
    s2 := s1 // 值拷贝
    fmt.Println(s2)
    s1.age = 100
    fmt.Println(s2.name)

    // 如果希望s3的值跟随s2保持一致怎么实现
    s3 := &s1 // var s4 *Student = &s2
    s1.age = 100
    fmt.Println((*s3).age)
    fmt.Println(s3.age)

    // 案例2
    var s4 = Student{sid: 1001, name: "alvin", age: 32}
    CourseInit(s4)
    fmt.Println("s报的课程:", s4.course)
    // 怎么能初始化成功呢?
    var s5 = &Student{sid: 1001, name: "alvin", age: 32}
    CourseInit2(s5)
    fmt.Println("s报的课程:", (*s5).course) // *s.course的写法是错误的
    fmt.Println("s报的课程:", s5.course)

}

在Go语言中,结构体指针的变量可以继续使用.,这是因为Go语言为了方便开发者访问结构体指针的成员变量可以像访问结构体的成员变量一样简单,使用了语法糖(Syntactic sugar)技术,将 instance.Name 形式转换为 (*instance).Name。

2.4、实例化之 new(结构体)

Go语言中,还可以使用 new 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。使用 new 的格式如下:其中:

instance := new(T)

其中:
T 为类型,可以是结构体、整型、字符串等。
instance:T 类型被实例化后保存到 instance 变量中,instance的类型为 *T,属于指针。

s := new(Student)              // &Student{}
fmt.Println(reflect.TypeOf(s)) // *Student
fmt.Println(s)                 // *Student
s.name = "yuan"
fmt.Println((*s).name)
fmt.Println(s.name)

4、模拟构造函数

Go语言没有构造函数,但是我们可以使用结构体初始化的过程来模拟实现构造函数。

package main

import "fmt"

type Student struct {
    sid    int
    name   string
    age    int8
    course []string //  选秀课程
}

func NewStudent(sid int, name string, age int8, course []string) *Student {
    return &Student{
        sid:    sid,
        name:   name,
        age:    age,
        course: course,
    }
}

func main() {

    s := NewStudent(1001, "yuan", 32, nil)
    fmt.Println(s)

}

5、方法接收器

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。
方法的定义格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
          函数体
}

其中,
接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是self、this之类的命名。例如,Person类型的接收者变量应该命名为 p,Connector类型的接收者变量应该命名为c等。
接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
方法名、参数列表、返回参数:具体格式与函数定义相同。

package main

import "fmt"

type Player struct {
    Name        string
    HealthPoint int
    Level       int
    NowPosition []int
    Prop        []string
}

func NewPlayer(name string, hp int, level int, np []int, prop []string) *Player {

    return &Player{
        name,
        hp,
        level,
        np,
        prop,
    }
}

func (p Player) attack() {
    fmt.Printf("%s发起攻击!\n", p.Name)
}
func (p *Player) attacked() {
    fmt.Printf("%s被攻击!\n", p.Name)
    p.HealthPoint -= 10
    fmt.Println(p.HealthPoint)
}

func (p *Player) buyProp(prop string) {
    p.Prop = append(p.Prop, prop)
    fmt.Printf("%s购买道具!\n", p.Name)
}

func main() {
    player := NewPlayer("yuan", 100, 100, nil, nil)
    player.attack()
    player.attacked()
    fmt.Println(player.HealthPoint)
    player.buyProp("魔法石")
    fmt.Println(player.Prop)
}

1、官方定义:Methods are not mixed with the data definition (the structs): they are orthogonal to types; representation(data) and behavior (methods) are independent
2、方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。

6、匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。

package main

import "fmt"

type Person struct {
    string
    int
}

func main() {
    p1 := Person{
        "yuan",
        18,
    }
    fmt.Printf("%#v\n", p1)        //main.Person{string:"yuan", int:18}
    fmt.Println(p1.string, p1.int) //北京 18
}

结构体也可以作为匿名字段使用

package main

import "fmt"

type Addr struct {
    country  string
    province string
    city     string
}

type Person struct {
    name string
    age  int
    Addr
}

func main() {
    p1 := Person{
        "yuan",
        18,
        Addr{"中国", "广东省", "深圳"},
    }
    fmt.Printf("%#v\n", p1)      //main.Person{string:"北京", int:18}
    fmt.Println(p1.name, p1.age) // yuan 18
    fmt.Println(p1.Addr)
    fmt.Println(p1.Addr.country) // 中国
    fmt.Println(p1.city)         // 深圳
}

当结构体中有和匿名字段相同的字段时,采用外层优先访问原则

7、结构体的继承

package main

import "fmt"

//Animal 动物
type Animal struct {
    name string
}

func (a *Animal) eat() {
    fmt.Printf("%s is eating!\n", a.name)
}
func (a *Animal) sleep() {
    fmt.Printf("%s is sleeping!\n", a.name)
}

// Dog 类型
type Dog struct {
    Kind    string
    *Animal //通过嵌套匿名结构体实现继承
}

func (d *Dog) bark() {
    fmt.Printf("%s is barking ~\n", d.name)
}

// Cat 类型
type Cat struct {
    *Animal
}

func (c *Cat) climbTree() {
    fmt.Printf("%s is climb tree ~\n", c.name)
}

func main() {
    d1 := &Dog{
        Kind: "金毛",
        Animal: &Animal{ //注意嵌套的是结构体指针
            name: "旺财",
        },
    }
    d1.eat()
    d1.bark()

    c1 := &Cat{
        Animal: &Animal{
            name: "喵喵",
        },
    }
    c1.sleep()
    c1.climbTree()

}

8、序列化

序列化: 通过某种方式把数据结构或对象写入到磁盘文件中或通过网络传到其他节点的过程。
反序列化:把磁盘中对象或者把网络节点中传输的数据恢复为python的数据对象的过程。

8.1、json初识

序列化最重要的就是json序列化。
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

在这里插入图片描述

8.2、结构体的json操作

package main

import (
    "encoding/json"
    "fmt"
)

type Addr struct {
    Province string
    City     string
}
type Stu struct {
    Name string `json:"name"` // 结构体的标签
    Age  int    `json:"-"`    // 表示不参与序列化
    Addr Addr
}

func main() {

    var stuMap = map[string]interface{}{"name": "yuan", "age": 32, "addr": "beijing"}
    var stuStruct = Stu{Name: "yuan", Age: 18, Addr: Addr{Province: "Hebei", City: "langFang"}}

    // 序列化
    jsonStuMap, _ := json.Marshal(stuMap)
    jsonStuStruct, _ := json.Marshal(stuStruct)

    fmt.Println(string(jsonStuMap))
    fmt.Println(string(jsonStuStruct))

    // 反序列化
    // var x  = make(map[int]string)
    var StuMap map[string]interface{}
    err := json.Unmarshal(jsonStuMap, &StuMap)
    if err != nil {
        return
    }
    fmt.Println("StuMap", StuMap, StuMap["name"])

    var StuStruct Stu
    err := json.Unmarshal(jsonStuStruct, &StuStruct)
    if err != nil {
        return
    }
    fmt.Println(StuStruct)
    fmt.Println(StuStruct.Name)
    fmt.Println(StuStruct.Addr.City)

}

章节作业

将客户关系管理系统改为结构体版本

package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

type Customer struct {
    Cid    int
    Name   string
    Gender string
    Age    int8
    Email  string
}

func NewCustomer(cid int, name string, gender string, age int8, email string) Customer {

    return Customer{
        Cid:    cid,
        Name:   name,
        Gender: gender,
        Age:    age,
        Email:  email,
    }
}

type CustomerService struct {
    customers   []Customer
    customersId int
}

func NewCustomerService(customers []Customer, customersId int) CustomerService {
    return CustomerService{customers, customersId}
}

func (cs *CustomerService) findById(id int) int {
    index := -1
    for i := 0; i < len(cs.customers); i++ {

        if cs.customers[i].Cid == id {
            index = i
        }
    }
    return index
}

func (cs *CustomerService) nextChoice() (b bool) {
    // 引导用户选择继续还是返回
    fmt.Print("返回上一层【回车】,继续该操作【C/c】,退出【Q/q】:")
    var Choice string
    fmt.Scanln(&Choice)
    if strings.ToUpper(Choice) == "C" {
        b = true
    } else if strings.ToUpper(Choice) == "Q" {
        os.Exit(0)
    }
    return
}

func (cs *CustomerService) addCustomer() {
    for true {
        // 引导用户输入学号和姓名
        fmt.Printf("\033[1;35;40m%s\033[0m\n", "---------------------------添加客户开始-----------------------------")
        // 引导用户输入
        var name string
        fmt.Print("请输入客户姓名:")
        fmt.Scan(&name)

        var gender string
        fmt.Print("请输入客户性别:")
        fmt.Scan(&gender)

        var age int8
        fmt.Print("请输入客户年龄:")
        fmt.Scan(&age)

        var email string
        fmt.Print("请输入客户邮箱:")
        fmt.Scan(&email)

        // 创建客户的map对象
        cs.customersId++ // 客户编号不需要输入,系统自增即可
        newCustomer := NewCustomer(cs.customersId, name, gender, age, email)
        // 添加客户map对象添加到客户切片中
        cs.customers = append(cs.customers, newCustomer)
        fmt.Printf("\033[1;35;40m%s\033[0m\n", "---------------------------添加客户完成-----------------------------")
        goOn := cs.nextChoice()
        if !goOn {
            break
        }
    }
}

func (cs *CustomerService) listCustomer() {
    for true {
        fmt.Printf("\033[1;32;40m%s\033[0m\n", "----------------------------------客户列表开始----------------------------")
        for _, customer := range cs.customers {
            fmt.Printf("\u001B[1;39;45m编号:%-8d 姓名:%-8s 性别:%-8s 年龄:%-8d 邮箱:%-10s \u001B[0m\n",
                customer.Cid, customer.Name, customer.Gender, customer.Age, customer.Email)
        }
        fmt.Printf("\033[1;32;40m%s\033[0m\n", "----------------------------------客户列表完成----------------------------")
        goOn := cs.nextChoice()
        if !goOn {
            break
        }
    }
}
func (cs *CustomerService) updateCustomer() {
    fmt.Printf("\033[1;36;40m%s\033[0m\n", "---------------------------客户修改开始----------------------------")
    for true {
        var updateCid int
        fmt.Print("请输入更新客户编号(-1退出):")
        fmt.Scan(&updateCid)
        if updateCid == -1 {
            return
        }
        updateIndex := cs.findById(updateCid)
        if updateIndex == -1 {
            fmt.Println("删除失败,输入的编号ID不存在")
            continue
        }

        // 引导用户输入
        var name string
        fmt.Printf("请输入客户姓名(%s):", cs.customers[updateIndex].Name)
        fmt.Scanln(&name)

        var gender string
        fmt.Printf("请输入客户性别(%s):", cs.customers[updateIndex].Gender)
        fmt.Scanln(&gender)

        var age int8
        fmt.Printf("请输入客户年龄(%d):", cs.customers[updateIndex].Age)
        fmt.Scanln(&age)

        var email string
        fmt.Printf("请输入客户邮箱(%s):", cs.customers[updateIndex].Email)
        fmt.Scanln(&email)

        if age != 0 {
            cs.customers[updateIndex].Age = age
        }
        if name != "" {
            cs.customers[updateIndex].Name = name
        }
        if gender != "" {
            cs.customers[updateIndex].Gender = gender
        }
        if email != "" {
            cs.customers[updateIndex].Email = email
        }

        fmt.Printf("\033[1;36;40m%s\033[0m\n", "---------------------------客户修改完成----------------------------")
        goOn := cs.nextChoice()
        if !goOn {
            break
        }
    }
}

func (cs *CustomerService) deleteCustomer() {
    for true {
        fmt.Printf("\033[1;31;40m%s\033[0m\n", "---------------------------删除客户开始----------------------------")
        var delCid int
        fmt.Print("请输入删除客户编号:")
        fmt.Scan(&delCid)

        delIndex := cs.findById(delCid)
        if delIndex == -1 {
            fmt.Println("删除失败,输入的编号ID不存在")
            continue
        }
        cs.customers = append(cs.customers[:delIndex], cs.customers[delIndex+1:]...)
        fmt.Printf("\033[1;31;40m%s\033[0m\n", "---------------------------删除客户完成----------------------")
        goOn := cs.nextChoice()
        if !goOn {
            break
        }
    }
}

func (cs *CustomerService) keepCustomers() {

    customersJsonBytes, _ := json.Marshal(cs.customers)
    err := ioutil.WriteFile("customers.json", customersJsonBytes, 0666)
    if err != nil {
        return
    }

    fmt.Printf("\033[1;31;40m%s\033[0m\n", "---------------------------保存完成----------------------")

}

func main() {
    var customers []Customer
    customersJsonBytes, err := ioutil.ReadFile("customers.json")
    if err != nil {
        return
    }
    json.Unmarshal(customersJsonBytes, &customers)
    cs := NewCustomerService(customers, customers[len(customers)-1].Cid)
    for true {
        fmt.Printf("\033[1;30;42m%s\033[0m\n", `
----------------客户信息管理系统--------------
           1、添加客户
           2、查看客户
           3、更新客户
           4、删除客户
           5、保存
           6、退出
-------------------------------------------
`)

        var choice int
        fmt.Printf("\033[1;38;40m%s\033[0m", "请输入选择【1-5】:")
        stdin := bufio.NewReader(os.Stdin)
        fmt.Fscan(stdin, &choice)

        switch choice {
        case 1:
            cs.addCustomer()
        case 2:
            cs.listCustomer()
        case 3:
            cs.updateCustomer()
        case 4:
            cs.deleteCustomer()
        case 5:
            cs.keepCustomers()
        case 6:
            os.Exit(0)
        default:
            fmt.Println("按要求输入数字,请重新输入")
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于linux下的高并发服务器开发(第三章)- 3.7 线程属性

int pthread_attr_init(pthread_attr_t *attr);- 初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *attr);- 释放线程属性的资源int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);- 获取线程分离的状态属性int pthread_attr_setdet…

【Redis】所以延迟双删有啥用

文章目录 1、何为延时双删2、常用缓存策略2.1、介绍2.2、先删缓存后更库2.3、先更库后删缓存2.4、使用场景 3、延时双删实现4、为什么要使用延时双删5、方案选择6、延时双删真的完美吗7、如何确定延时的时间 1、何为延时双删 延迟双删&#xff08;Delay Double Delete&#xf…

Jupyter 安装、简单操作及工作路径更换

一、Jupyter下载安装 pip install jupyterAnaconda是Python另一个非常流行的发行版&#xff0c;它之后有着自己的叫做“conda”的安装工具。用户可以使用它来安装很多第三方包。然而&#xff0c;Anaconda会预装很多包&#xff0c;包括了Jupyter Notebook,所以若已经安装了Anac…

VUE3 语法教程

vue3 起步 刚开始学习 Vue&#xff0c;我们不推荐使用 vue-cli 命令行工具来创建项目&#xff0c;更简单的方式是直接在页面引入 vue.global.js 文件来测试学习。 Vue3 中的应用是通过使用 createApp 函数来创建的&#xff0c;语法格式如下&#xff1a; const app Vue.crea…

cmder 使用简介

文章目录 1. cmder 简介2. 下载地址3. 安装4. 配置环境变量5. 添加 cmder 到右键菜单6. 解决中文乱码问题 1. cmder 简介 cmder 是一个增强型命令行工具&#xff0c;不仅可以使用 windows 下的所有命令&#xff0c;更爽的是可以使用 linux的命令, shell 命令。 2. 下载地址 …

机器学习深度学习——预备知识(下)

机器学习&&深度学习——预备知识&#xff08;下&#xff09; 4 微积分4.1 导数和微分4.2 偏导数4.3 梯度4.4 链式法则 5 自动微分5.1 简单例子5.2 非标量变量的反向传播5.3 分离计算5.4 Python控制流的梯度计算 6 概率6.1 基本概率论6.1.1 概率论公理 6.2 处理多个随机…

5.1 Bootstrap 插件概览

文章目录 Bootstrap 插件概览data 属性编程方式的 API避免命名空间冲突事件 Bootstrap 插件概览 在前面 布局组件 章节中所讨论到的组件仅仅是个开始。Bootstrap 自带 12 种 jQuery 插件&#xff0c;扩展了功能&#xff0c;可以给站点添加更多的互动。即使您不是一名高级的 Jav…

超参数优化 - 贝叶斯优化的实现

目录 1. 基于Bayes_opt实现GP优化 1.1 定义目标函数 1.2 定义参数空间 1.3 定义优化目标函数的具体流程 4. 定义验证函数&#xff08;非必须&#xff09; 5. 执行实际优化流程 2. 基于HyperOpt实现TPE优化 2.1 定义目标函数 2.2 定义参数空间 2.3 定义优化目标函数的…

Asp.Net WebForm ViewState

ViewState用于保存服务器控件(runat"server")状态便于在触发回调后&#xff08;PostBack&#xff09;恢复页面。 页面拖入一个Form id"form1" runat"server",里面添加一个<asp:Button id"Button1" Text"删除" OnClick&q…

python:对 GEDI 数据进行高斯滤波处理

作者:CSDN @ _养乐多_ 在本篇博客中,我们将学习如何使用 Python 对 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据进行高斯滤波处理。高斯滤波是一种平滑滤波方法,可以有效减少噪声和突变,提高数据的平滑性和连续性。我们将使用 pandas 和 scipy.signal 库…

STM32MP157驱动开发——LED 驱动( GPIO 子系统)

文章目录 编写思路GPIO子系统的LED驱动程序(stm32mp157)如何找到引脚功能和配置信息在设备树中添加 Pinctrl 信息leddrv.cledtest.cMakefile编译测试 编写思路 阅读&#xff1a;STM32MP157驱动开发——GPIO 和 和 Pinctrl 子系统的概念可知利用GPIO子系统去编写LED驱动&#x…

Mysql基础(下)之函数,约束,多表查询,事务

&#x1f442; 回到夏天&#xff08;我多想回到那个夏天&#xff09; - 傲七爷/小田音乐社 - 单曲 - 网易云音乐 截图自 劈里啪啦 -- 黑马Mysql&#xff0c;仅学习使用 &#x1f447;原地址 47. 基础-多表查询-表子查询_哔哩哔哩_bilibili 目录 &#x1f982;函数 &#x1f3…

Spark(35):Structured Streaming 概述

目录 0. 相关文章链接 1. 什么是Structured Streaming 2. Structure Streaming 快速入门 2.1. 导入依赖 2.2. 代码实现 2.3. 程序测试 2.4. 代码说明 0. 相关文章链接 Spark文章汇总 1. 什么是Structured Streaming 从 spark2.0 开始, spark 引入了一套新的流式计算模…

新Viewport单位

本文为翻译本文译者为 360 奇舞团前端开发工程师原文标题&#xff1a;New Viewport Units原文作者&#xff1a;Ahmad Shadeed原文地址&#xff1a;https://ishadeed.com/article/new-viewport-units/ 自 2012 年以来&#xff0c;我们一直在使用 CSS viewport 单位。它们对于帮助…

RGB简单人脸活体检测(Liveness Detection)

参考&#xff1a; https://github.com/minivision-ai/Silent-Face-Anti-Spoofing&#xff08;主要这个库&#xff09; https://github.com/computervisioneng/face-attendance-system&#xff08;使用案例&#xff09; ##概念&#xff1a; 活体检测是指针对人脸识别过程中的人脸…

TSDB - VictoriaMetrics 技术原理浅析

一、前言 在监控领域&#xff0c;通常需要指标存储组件TSDB&#xff0c;目前开源的TSDB组件比较多&#xff0c;各个组件性能、高可用性、维护成本等等各有差异。本文不分析选型问题&#xff0c;重点讲解VictoriaMetrics&#xff08;后面简称为vm&#xff09;。 有兴趣的朋友建议…

Linux中常用的一些shell命令

很多的时候我们知道有一个命令&#xff0c;但不知道它的详细用法&#xff0c;可以来搜索下。但有些时候压根不知道有这个命令&#xff0c;比如vimdiff和diff这两个命令&#xff0c;知道人就比较少。 本节内容主要汇总一下Linux中常用的一些shell命令。 1. 文件和目录操作 ls …

win11安装MySQL5.7.43的问题清单

文章目录 1、win11查看自己电脑有没有安装mysql法1法2 2、完全清除之前安装的mysql3、 mysql的安装法1法2 4、遇到的一些问题1) ‘mysql‘不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件2) 忘记mysql的密码3)mysql启动不了:本地计算机上的MySQL服务启动后停止4…

机器学习深度学习——torch.nn模块

机器学习&&深度学习——torch.nn模块 卷积层池化层激活函数循环层全连接层 torch.nn模块包含着torch已经准备好的层&#xff0c;方便使用者调用构建网络。 卷积层 卷积就是输入和卷积核之间的内积运算&#xff0c;如下图&#xff1a; 容易发现&#xff0c;卷积神经网…

汽车养护店服务难题,看帕凝怎样解决?

中国汽车市场庞大&#xff0c;入户已然成为标配&#xff0c;加之新能源汽车近些年高增量&#xff0c;更促进了行业增长。而汽车后市场也迎来了一系列变化&#xff0c;客户服务前后路径需完善&#xff0c;商家们应该如何数字化经营呢&#xff1f; 接下来让我们看看【帕凝汽车养…