当前位置: 首页 > article >正文

Golang——7、包与接口详解

包与接口详解

  • 1、Golang包详解
    • 1.1、Golang中包的定义和介绍
    • 1.2、Golang包管理工具go mod
    • 1.3、Golang中自定义包
    • 1.4、Golang中使用第三包
    • 1.5、init函数
  • 2、接口详解
    • 2.1、接口的定义
    • 2.2、空接口
    • 2.3、类型断言
    • 2.4、结构体值接收者和指针接收者实现接口的区别
    • 2.5、一个结构体实现多个接口
    • 2.6、接口嵌套
    • 2.7、空接口和类型断言使用细节

1、Golang包详解

1.1、Golang中包的定义和介绍

包(package)是多个 Go 源码的集合,是一种高级的代码复用方案,Go语言为我们提供了很多内置包,如fmt、strconv、strings、sort、errors、time、encoding/json、os、io等。
Golang 中的包可以分为三种:1、系统内置包。2、自定义包。3、第三方包。
系统内置包: Golang语言给我们提供的内置包,引入后可以直接使用,如 fmt、 strconv、 strings、sort、errors、time、encoding/json、os、io等。
自定义包:开发者自己写的包。
第三方包:属于自定义包的一种,需要下载安装到本地后才可以使用,如前面给大家介绍的。
"github.com/shopspring/decimal"包解决float精度丢失问题。

1.2、Golang包管理工具go mod

在Golang1.11版本之前如果我们要自定义包的话必须把项目放在GOPATH 目录。Go1.11版本之后无需手动配置环境变量,使用 go mod 管理项目,也不需要非得把项目放到 GOPATH指定目录下,你可以在你磁盘的任何位置新建一个项目,Go1.13 以后可以彻底不要GOPATH了。

首先在项目路径下使用go mod init 文件名,来初始化项目,生成一个go.mod文件。
在这里插入图片描述
注意,这个文件名必须是当前所在目录下的文件名,比如当前我在demo60目录下,因此文件名就是demo60。

在这里插入图片描述
另外,使用命令go mod可以查看其他选项,在这些选项中我们最常用的就是init和tidy。
其中go mod tidy表示增加丢失的module,去掉未用的module,当我们执行这个指令后,就会自动将我们需要包下载下来,将不需要的包去除。


1.3、Golang中自定义包

包(package)是多个Go源码的集合,一个包可以简单理解为一个存放多个.go文件的文件夹。该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属的包。
在这里插入图片描述
如图:我们在demo60目录下创建一个clac目录,并创建一个clac。

package mainimport ("demo60/clac""fmt"
)func main() {res1 := clac.Add(5, 10)res2 := clac.Sub(5, 10)fmt.Println(res1, res2)
}

接着我们在main.go中引入我们自定义的clac包,并调用里面的Add和Sub方法。
在这里插入图片描述

同时我们需要注意,在clac这个包中,可以定义变量和函数,但是必须是大写的,大写的表示公有属性,可以被其他包访问,小写表示私有属性,不能被其他包使用。


当然我们也可以引入多个包,例如我们在demo60目录下创建一个tools文件夹,里面再定义几个.go文件,但他们都属于同一个包tools。
在这里插入图片描述

package toolsimport "fmt"func PrintInfo() {fmt.Println("hello world")
}
package toolsfunc Mul(x, y int) int {return x * y
}

然后我们在main.go中调用这两个函数。

package mainimport ("demo60/clac""demo60/tools""fmt"
)func main() {res1 := clac.Add(5, 10)res2 := clac.Sub(5, 10)fmt.Println(res1, res2)fmt.Println(clac.AA)fmt.Println(tools.Mul(2, 3))tools.PrintInfo()
}

在这里插入图片描述
上面就演示了我们自定义了两个包clac和tools,并通过import引入使用。


另外,我们也可以匿名导入一个包,不过在现在vscode的go语法已经非常智能了,所以基本上就用不到了。
例如下面这种情况,我们导入了一个fmt包,但是并没有使用,我们可以在前面加上_

package mainimport _ "fmt"func main() {}

我们也可以给导入的包起别名,比如我们导入的一个包名字过长,我们就可以给他起个别名。

package mainimport f "fmt"func main() {f.Println("hello world")
}

在这里插入图片描述


1.4、Golang中使用第三包

之前我们说过,Golang中的浮点数类型是有精度丢失的,所以我们可以使用第三方包decimal,下面演示如何使用第三方包decimal。
首先在项目目录下执行go mod init初始化项目,然后实现main.go文件。

package mainimport ("fmt""github.com/shopspring/decimal"
)func main() {num1 := 8.2num2 := 3.8d1 := decimal.NewFromFloat(num1).Add(decimal.NewFromFloat(num2))fmt.Println(d1)
}

当我们这样写好代码保存后是无法运行的,因为我们并没有第三方包decimal。
所以这里就需要使用之前的go mod tidy。它会自动根据我们的文件查找是否有缺少的包,或者不需要使用的包。

在这里插入图片描述


1.5、init函数

在Go语言程序执行时导入包语句会自动触发包内部init()函数的调用。需要注意的是:init()函数没有参数也没有返回值。init()函数在程序运行时自动被调用执行,不能在代码中主动调用它。
在这里插入图片描述

Go语言包会从main包开始检查其导入的所有包,每个包中又可能导入了其他的包。Go 编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
在运行时,被最后导入的包会最先初始化并调用其init()函数,如下图示:

在这里插入图片描述
有点类似DFS的感觉。


2、接口详解

Golang中的接口是一种抽象数据类型,Golang中接口定义了对象的行为规范,只定义规范不实现。接口中定义的规范由具体的对象来实现。
通俗的讲接口就一个标准,它是对一个对象的行为和规范进行约定,约定实现接口的对象必须得按照接口的规范。

2.1、接口的定义

在Golang中接口(interface)是一种类型,函数method的集合,Golang中的接口不能包含任何变量。一种抽象的类型。接口(interface)是一组在Golang中接口中的所有方法都没有方法体,接口定义了一个对象的行为规范,只定义规范不实现。接口体现了程序设计的多态和高内聚低耦合的思想Golang中的接口也是一种数据类型,不需要显示实现。只需要一个变量含有接口类型中的所有方法,那么这个变量就实现了这个接口。
在这里插入图片描述
其中:
• 接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。 接口名最好要能突出该接口的类型含义。
• 方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
• 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。

实现一个Usber接口规范,接着让手机和相机实现这个接口。

package mainimport "fmt"type Usber interface {start()stop()
}type Phone struct {Name string
}func (p Phone) start() {fmt.Printf("%v启动\n", p.Name)
}func (p Phone) stop() {fmt.Printf("%v关闭\n", p.Name)
}type Camera struct {Name string
}func (c Camera) start() {fmt.Printf("%v启动\n", c.Name)
}func (c Camera) stop() {fmt.Printf("%v关闭\n", c.Name)
}func main() {p := Phone{"小米手机",}c := Camera{"哈苏相机",}var u1, u2 Usber // Golang中接口就是一个数据类型u1 = p           // 表示Phone实现接口Usberu2 = c           // 表示Camera实现接口Usberu1.start()u1.stop()u2.start()u2.stop()
}

在这里插入图片描述

下面我们可以再实现一个Computer结构体,然后实现它的一个方法work,该方法必须传入一个Usber接口。

package mainimport "fmt"type Usber interface {start()stop()
}type Phone struct {Name string
}func (p Phone) start() {fmt.Printf("%v启动\n", p.Name)
}func (p Phone) stop() {fmt.Printf("%v关闭\n", p.Name)
}type Camera struct {Name string
}func (c Camera) start() {fmt.Printf("%v启动\n", c.Name)
}func (c Camera) stop() {fmt.Printf("%v关闭\n", c.Name)
}type Computer struct {
}func (c Computer) work(u Usber) {u.start()u.stop()
}func main() {p := Phone{"小米手机",}c := Camera{"哈苏相机",}computer := Computer{}computer.work(p)computer.work(c)
}

2.2、空接口

Golang中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口。空接口表示没有任何约束,因此任何类型变量都可以实现空接口。空接口在实际项目中用的是非常多的,用空接口可以表示任意数据类型。

1、定义空接口
空接口表示没有任何约束,任何类型都可以实现空接口。

package mainimport "fmt"type A interface{}func main() {var a Avar str = "你好golang"a = strfmt.Printf("值: %v, 类型: %T\n", a, a)var num = 10a = numfmt.Printf("值: %v, 类型: %T\n", a, a)var flag = truea = flagfmt.Printf("值: %v, 类型: %T\n", a, a)
}

在这里插入图片描述

2、空接口作为函数参数

package mainimport "fmt"func show(a interface{}) {fmt.Printf("值: %v, 类型: %T\n", a, a)
}func main() {show(20)show("你好golang")show([]int{1, 2, 3, 4, 5})
}

在这里插入图片描述

3、map的值实现空接口,使用空接口实现可以保存任意值的字典。

package mainimport "fmt"func main() {var m = make(map[string]interface{})m["username"] = "张三"m["age"] = 18m["hobby"] = []string{"跑步", "爬山", "写代码"}fmt.Printf("值: %v, 类型: %T\n", m, m)
}

在这里插入图片描述

4、切片实现空接口。

var slice = []interface{}{"张三", 18, true, 33.22}
fmt.Printf("值: %v, 类型: %T\n", slice, slice)

在这里插入图片描述


2.3、类型断言

一个接口的值 (简称接口值) 是由一个具体类型和具体类型的值两部分组成的。 这两部分分别称为接口的动态类型和动态值。
如果我们想要判断空接口中值的类型,那么这个时候就可以使用类型断言,其语法格式:

x.(T)

其中:
• x :表示类型为interface{}的变量
• T:表示断言x可能是的类型。

该语法返回两个参数,第一个参数是x转化为 T 类型后的变量,第二个值是一个布尔值,若为true则表示断言成功,为 alse则表示断言失败。

1、基本使用。

package mainimport "fmt"func main() {var x interface{}x = "hello golang"v, ok := x.(string)if ok {fmt.Printf("类型为string, 值: %v\n", v)} else {fmt.Println("类型断言失败")}
}

在这里插入图片描述

2、定义一个方法,可以传入任意类型,然后根据不同的类型实现不同的功能。
下面实现两种方式:if-else和switch-case。

package mainimport "fmt"func MyPrint1(x interface{}) {if _, ok := x.(string); ok {fmt.Println("string类型")} else if _, ok := x.(int); ok {fmt.Println("int类型")} else if _, ok := x.(bool); ok {fmt.Println("bool类型")}
}func MyPrint2(x interface{}) {switch x.(type) {case string:fmt.Println("string类型")case int:fmt.Println("int类型")case bool:fmt.Println("bool类型")default:fmt.Println("传入错误...")}
}func main() {MyPrint1("你好golang")MyPrint2(12)
}

在这里插入图片描述
注意:x.(type)只能结合switch语句使用。


针对前面的实现的Computer,我们判断传入的类型然后实现对应的方法。有点类似于C++中的多肽。

package mainimport "fmt"type Usber interface {start()stop()
}type Phone struct {Name string
}func (p Phone) start() {fmt.Printf("%v启动\n", p.Name)
}func (p Phone) stop() {fmt.Printf("%v关闭\n", p.Name)
}type Camera struct {Name string
}func (c Camera) start() {fmt.Printf("%v启动\n", c.Name)
}func (c Camera) stop() {fmt.Printf("%v关闭\n", c.Name)
}type Computer struct {
}func (c Computer) work(u Usber) {if _, ok := u.(Phone); ok {u.start()} else if _, ok := u.(Camera); ok {u.stop()}
}
func main() {p := Phone{"小米手机",}c := Camera{"哈苏x2d",}com := Computer{}com.work(p)com.work(c)
}

在work函数中我们实现类型断言,如果是Phone类型就执行start函数,如果是Camera类型就执行stop函数。


2.4、结构体值接收者和指针接收者实现接口的区别

package mainimport "fmt"type Usber interface {start()stop()
}type Phone struct {Name string
}func (p Phone) start() {fmt.Printf("%v启动!\n", p.Name)
}func (p Phone) stop() {fmt.Printf("%v关闭!\n", p.Name)
}func main() {var u Usbervar p1 = Phone{"小米手机",}u = p1u.start()u.stop()var p2 = &Phone{"苹果手机",}u = p2u.start()u.stop()
}

在这里插入图片描述
根据现象,如果结构体中的方法是值接受者,那么实例化后的结构体值类型和指针类型都可以赋值给接口变量。

将start和stop方法改为指针接受者类型*Phone,那么结构体值类型就无法复制给接口变量了,此时只有指针类型可以赋值给接口变量。

另外如果要修改结构体内的成员变量,必须采用指针接受者的方式,如下:

package mainimport "fmt"type Animaler interface {setName(name string)getName() string
}type Dog struct {Name string
}func (d *Dog) setName(name string) {d.Name = name
}func (d Dog) getName() string {return d.Name
}func main() {d := &Dog{Name: "小柴",}var a Animalera = dfmt.Println(a.getName())a.setName("小奇")fmt.Println(a.getName())
}

在这里插入图片描述


2.5、一个结构体实现多个接口

package mainimport "fmt"type Animaler1 interface {getName() string
}type Animaler2 interface {setName(name string)
}type Dog struct {Name string
}func (d Dog) getName() string {return d.Name
}func (d *Dog) setName(name string) {d.Name = name
}func main() {d := &Dog{Name: "小柴",}var a1 Animaler1var a2 Animaler2a1 = da2 = dfmt.Println(a1.getName())a2.setName("小奇")fmt.Println(a1.getName())
}

在这里插入图片描述


2.6、接口嵌套

package mainimport "fmt"type Ainterface interface {SetName(name string)
}type Binterface interface {GetName() string
}type Animaler interface {AinterfaceBinterface
}type Dog struct {Name string
}func (d Dog) GetName() string {return d.Name
}func (d *Dog) SetName(name string) {d.Name = name
}func main() {d := &Dog{Name: "小柴",}var a Animalera = dfmt.Println(a.GetName())a.SetName("小奇")fmt.Println(a.GetName())
}

在这里插入图片描述


2.7、空接口和类型断言使用细节

下面的代码有没有问题?

package mainimport "fmt"type Address struct {Name  stringPhone string
}func main() {var m = make(map[string]interface{})m["username"] = "张三"m["age"] = 20m["hobby"] = []string{"跑步", "爬山", "写代码"}fmt.Println(m["username"])fmt.Println(m["age"])fmt.Println(m["hobby"])fmt.Println(m["hobby"][0])
}

在这里插入图片描述
可以看到报错了,不支持这么访问。

再来看另一种情况:

m["address"] = Address{Name:  "李四",Phone: "13912344321",
}
fmt.Println(m["address"])
fmt.Println(m["address"].Name)

在这里插入图片描述
这样也是不支持的。

解决办法,实现类型断言接受后再访问:

package mainimport "fmt"type Address struct {Name  stringPhone string
}func main() {var m = make(map[string]interface{})m["username"] = "张三"m["age"] = 20m["hobby"] = []string{"跑步", "爬山", "写代码"}fmt.Println(m["username"])fmt.Println(m["age"])fmt.Println(m["hobby"])hobby, _ := m["hobby"].([]string)fmt.Println(hobby[0], hobby[1], hobby[2])m["address"] = Address{Name:  "李四",Phone: "13912344321",}fmt.Println(m["address"])address, _ := m["address"].(Address)fmt.Println(address.Name, address.Phone)
}

在这里插入图片描述

相关文章:

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...

日常一水C

多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘&#xf…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析,分为​​已启动​​和​​未启动​​两种场景: 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​:当其他组件(如Activity、Service)通过ContentR…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制

目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...