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

《Go 语言第一课》课程学习笔记(十一)

控制结构

if 的“快乐路径”原则

  • 针对程序的分支结构,Go 提供了 if 和 switch-case 两种语句形式;而针对循环结构,Go 只保留了 for 这一种循环语句形式。

if 语句

  • if 语句是 Go 语言中提供的一种分支控制结构,它也是 Go 中最常用、最简单的分支控制结构。它会根据布尔表达式的值,在两个分支中选择一个执行。
  • 虽然各种编程语言几乎都原生支持了 if 语句,但 Go 的 if 语句依然有着自己的特点:
    • 第一,和 Go 函数一样,if 语句的分支代码块的左大括号与 if 关键字在同一行上,这也是 Go 代码风格的统一要求,gofmt 工具会帮助我们实现这一点;
    • 第二,if 语句的布尔表达式整体不需要用括号包裹,一定程度上减少了开发人员敲击键盘的次数。而且,if 关键字后面的条件判断表达式的求值结果必须是布尔类型,即要么是 true,要么是 false。
    • 如果判断的条件比较多,我们可以用多个逻辑操作符连接起多个条件判断表达式,比如这段代码就是用了多个逻辑操作符 && 来连接多个布尔表达式:
      if (runtime.GOOS == "linux") && (runtime.GOARCH == "amd64") &&
      (runtime.Compiler != "gccgo") {println("we are using standard go compiler on linux os for amd64")
      }
      
      在这里插入图片描述
  • Go 语言的 if 语句还有其他多种形式,比如二分支结构和多(N)分支结构。多分支结构引入了 else if。

支持声明 if 语句的自用变量

  • 无论是单分支、二分支还是多分支结构,我们都可以在 if 后的布尔表达式前,进行一些变量的声明,在 if 布尔表达式前声明的变量,称为 if 语句的自用变量。顾名思义,这些变量只可以在 if 语句的代码块范围内使用。
  • 在 if 语句中声明自用变量是 Go 语言的一个惯用法,这种使用方式直观上可以让开发者有一种代码行数减少的感觉,提高可读性。同时,由于这些变量是 if 语句自用变量,它的作用域仅限于 if 语句的各层隐式代码块中,if 语句外部无法访问和更改这些变量,这就让这些变量具有一定隔离性,这样你在阅读和理解 if 语句的代码时也可以更聚焦。

if 语句的“快乐路径”原则

  • 从可读性上来看,单分支结构要优于二分支结构,二分支结构又优于多分支结构。那么显然,我们在日常编码中要减少多分支结构,甚至是二分支结构的使用,这会有助于我们编写出优雅、简洁、易读易维护且不易错的代码。
  • if 语句的“快乐路径(Happy Path)”原则
    • 仅使用单分支控制结构;
    • 当布尔表达式求值为 false 时,也就是出现错误时,在单分支中快速返回;
    • 正常逻辑在代码布局上始终“靠左”,这样读者可以从上到下一眼看到该函数正常逻辑的全貌;
    • 函数执行到最后一行代表一种成功状态。

Go 中的 switch 语句

认识 switch 语句

  • 除了 if 语句之外,Go 语言还提供了一种更适合多路分支执行的分支控制结构,也就是 switch 语句。
  • 在一些执行分支较多的场景下,使用 switch 分支控制语句可以让代码更简洁,可读性更好。
  • Go 语言中 switch 语句的一般形式:
    switch initStmt; expr {case expr1:// 执行分支1case expr2:// 执行分支2case expr3_1, expr3_2, expr3_3:// 执行分支3case expr4:// 执行分支4... ...case exprN:// 执行分支Ndefault:// 执行默认分支
    }
    
    • 首先看这个 switch 语句一般形式中的第一行,这一行由 switch 关键字开始,它的后面通常接着一个表达式(expr),这句中的 initStmt 是一个可选的组成部分。
    • 我们可以在 initStmt 中通过短变量声明定义一些在 switch 语句中使用的临时变量。
    • 接下来,switch 后面的大括号内是一个个代码执行分支,每个分支以 case 关键字开始,每个 case 后面是一个表达式或是一个逗号分隔的表达式列表。
    • 这里还有一个以 default 关键字开始的特殊分支,被称为默认分支。
    • 最后,我们再来看 switch 语句的执行流程。switch 语句会用 expr 的求值结果与各个 case 中的表达式结果进行比较,如果发现匹配的 case,也就是 case 后面的表达式,或者表达式列表中任意一个表达式的求值结果与 expr 的求值结果相同,那么就会执行该 case 对应的代码分支,分支执行后,switch 语句也就结束了。
    • 如果所有 case 表达式都无法与 expr 匹配,那么程序就会执行 default 默认分支,并且结束 switch 语句。
    • Go 先对 switch expr 表达式进行求值,然后再按 case 语句的出现顺序,从上到下进行逐一求值。在带有表达式列表的 case 语句中,Go 会从左到右,对列表中的表达式进行求值。

switch 语句的灵活性

  • C 语言中的 switch 语句对表达式类型有限制,每个 case 语句只可以有一个表达式。而且,除非你显式使用 break 跳出,程序默认总是执行下一个 case 语句。这些特性开发人员带来了使用上的心智负担。
  • 相较于 C 语言中 switch 语句的“死板”,Go 的 switch 语句表现出极大的灵活性,主要表现在如下几方面:
    • 首先,switch 语句各表达式的求值结果可以为各种类型值,只要它的类型支持比较操作就可以了。
      • C 语言中,switch 语句中使用的所有表达式的求值结果只能是 int 或枚举类型,其他类型都会被 C 编译器拒绝。
      • Go 语言就宽容得多了,只要类型支持比较操作,都可以作为 switch 语句中的表达式类型。比如整型、布尔类型、字符串类型、复数类型、元素类型都是可比较类型的数组类型,甚至字段类型都是可比较类型的结构体类型,也可以。
        type person struct {name stringage int
        } 
        func main() {p := person{"tom", 13}switch p {case person{"tony", 33}:println("match tony")case person{"tom", 13}:println("match tom")case person{"lucy", 23}:println("match lucy")default:println("no match")}
        }
        
    • 第二点:switch 语句支持声明临时变量。
    • 第三点:case 语句支持表达式列表。
    • 第四点:取消了默认执行下一个 case 代码逻辑的语义。

type switch

  • "type switch”这是一种特殊的 switch 语句用法:
    func main() {var x interface{} = 13switch x.(type) {case nil:println("x is nil")case int:println("the type of x is int")case string:println("the type of x is string")case bool:println("the type of x is string")default:println("don't support the type")}
    }
    
    • switch 关键字后面跟着的表达式为 x.(type),这种表达式形式是 switch 语句专有的,而且也只能在 switch 语句中使用。这个表达式中的 x 必须是一个接口类型变量,表达式的求值结果是这个接口类型变量对应的动态类型。
    • 接着,case 关键字后面接的就不是普通意义上的表达式了,而是一个个具体的类型。这样,Go 就能使用变量 x 的动态类型与各个 case 中的类型进行匹配,之后的逻辑就都是一样的了。
  • Go 语言规范中明确规定,不带 label 的 break 语句中断执行并跳出的,是同一函数内 break 语句所在的最内层的 for、switch 或 select。

Go 的 for 循环

for 语句的经典使用形式

  • 主流编程语言都提供了对循环结构的支持,绝大多数主流语言,包括 C 语言、C++、Java 和 Rust,甚至连动态语言 Python 还提供了不止一种的循环语句,但 Go 却只有一种,也就是 for 语句。
  • Go 语言中 for 循环语句的经典形式:
    var sum int
    for i := 0; i < 10; i++ {sum += i
    }
    println(sum)
    

在这里插入图片描述

  • 图中①对应的组成部分执行于循环体(③ )之前,并且在整个 for 循环语句中仅会被执行一次,它也被称为循环前置语句。
    • 我们通常会在这个部分声明一些循环体(③ )或循环控制条件(② )会用到的自用变量,也称循环变量或迭代变量,比如这里声明的整型变量 i。
    • 与 if 语句中的自用变量一样,for 循环变量也采用短变量声明的形式,循环变量的作用域仅限于 for 语句隐式代码块范围内。
  • 图中②对应的组成部分,是用来决定循环是否要继续进行下去的条件判断表达式。
    • 和 if 语句的一样,这个用于条件判断的表达式必须为布尔表达式,如果有多个判断条件,我们一样可以由逻辑操作符进行连接。
    • 当表达式的求值结果为 true 时,代码将进入循环体(③)继续执行,相反则循环直接结束,循环体(③)与组成部分④都不会被执行。
  • 图中③对应的组成部分是 for 循环语句的循环体。
    • 如果相关的判断条件表达式求值结构为 true 时,循环体就会被执行一次,这样的一次执行也被称为一次迭代(Iteration)。
    • 在上面例子中,循环体执行的动作是将这次迭代中变量 i 的值累加到变量 sum 中。
  • 图中④对应的组成部分会在每次循环体迭代之后执行,也被称为循环后置语句。
    • 这个部分通常用于更新 for 循环语句组成部分①中声明的循环变量,比如在这个例子中,我们在这个组成部分对循环变量 i 进行加 1 操作。
  • Go 语言的 for 循环支持声明多循环变量,并且可以应用在循环体以及判断条件中:
    for i, j, k := 0, 1, 2; (i < 20) && (j < 10) && (k < 30); i, j, k = i+1, j+1,sum += (i + j + k)println(sum)
    }
    
    • 除了循环体部分之外,其余的三个部分都是可选的。
    • 虽然对前置语句或后置语句进行了省略,但经典 for 循环形式中的分号依然被保留着,这是 Go 语法的要求。
    • 当循环前置与后置语句都省略掉,仅保留循环判断条件表达式时,我们可以省略经典 for 循环形式中的分号。
    • 当 for 循环语句的循环判断条件表达式的求值结果始终为 true 时,我们就可以将它省略掉了。这个 for 循环就是我们通常所说的“无限循环”。

for range 循环形式

  • 针对像切片这样的复合数据类型,还有 Go 原生的字符串类型(string),Go 语言提供了一个更方便的“语法糖”形式:for range。
    var sl = []int{1, 2, 3, 4, 5}
    for i, v := range sl {fmt.Printf("sl[%d] = %d\n", i, v)
    }
    
    • for range 循环形式与 for 语句经典形式差异较大,除了循环体保留了下来,其余组成部分都“不见”了。其实那几部分已经被融合到 for range 的语义中了。
    • 这里的 i 和 v 对应的是经典 for 语句形式中循环前置语句的循环变量,它们的初值分别为切片 sl 的第一个元素的下标值和元素值。
    • 隐含在 for range 语义中的循环控制条件判断为:是否已经遍历完 sl 的所有元素,等价于i < len(sl)这个布尔表达式。
    • 每次迭代后,for range 会取出切片 sl 的下一个元素的下标和值,分别赋值给循环变量 i 和 v,这与 for 经典形式下的循环后置语句执行的逻辑是相同的。
  • for range 语句也有几个常见“变种”:
    • 变种一:当我们不关心元素的值时,我们可以省略代表元素值的变量 v,只声明代表下标值的变量 i。
    • 变种二:如果我们不关心元素下标,只关心元素值,那么我们可以用空标识符替代代表下标值的变量 i。这里一定要注意,这个空标识符不能省略,否则就与上面的“变种一”形式一样了,Go 编译器将无法区分。
    • 变种三:如果我们既不关心下标值,也不关心元素值,可以将 i,v 都省略。

string 类型

  • for range 对于 string 类型来说,每次循环得到的 v 值是一个 Unicode 字符码点,也就是 rune 类型值,而不是一个字节,返回的第一个值 i 为该 Unicode 字符码点的内存编码(UTF-8)的第一个字节在字符串内存序列中的位置。
  • 使用 for 经典形式与使用 for range 形式,对 string 类型进行循环操作的语义是不同的。

map

  • map 就是一个键值对(key-value)集合,最常见的对 map 的操作,就是通过 key 获取其对应的 value 值。但有些时候,我们也要对 map 这个集合进行遍历,这就需要 for 语句的支持了。
  • 但在 Go 语言中,我们要对 map 进行循环操作,for range 是唯一的方法,for 经典循环形式是不支持对 map 类型变量的循环控制的。
  • for range 对于 map 类型来说,每次循环,循环变量 k 和 v 分别会被赋值为 map 键值对集合中一个元素的 key 值和 value 值。

channel

  • channel 是 Go 语言提供的并发设计的原语,它用于多个 Goroutine 之间的通信。
  • 当 channel 类型变量作为 for range 语句的迭代对象时,for range 会尝试从 channel 中读取数据,使用形式是这样的:
    var c = make(chan int)
    for v := range c {// ...
    }
    
    • for range 每次从 channel 中读取一个元素后,会把它赋值给循环变量 v,并进入循环体。当 channel 中没有数据可读的时候,for range 循环会阻塞在对 channel 的读操作上。
    • 直到 channel 关闭时,for range 循环才会结束,这也是 for range 循环与 channel 配合时隐含的循环判断条件。

带 label 的 continue 语句

  • 日常开发中,出于算法逻辑的需要,我们可能会有中断当前循环体并继续下一次迭代的时候,也会有中断循环体并彻底结束循环语句的时候。针对这些情况,Go 语言提供了 continue 语句和 break 语句。
    • 如果循环体中的代码执行到一半,要中断当前迭代,忽略此迭代循环体中的后续代码,并回到 for 循环条件判断,尝试开启下一次迭代,这个时候我们可以使用 continue 语句来应对。
    • Go 语言中的 continue 在 C 语言 continue 语义的基础上又增加了对 label 的支持。
      • label 语句的作用,是标记跳转的目标。
        func main() {var sum intvar sl = []int{1, 2, 3, 4, 5, 6}
        loop:for i := 0; i < len(sl); i++ {if sl[i]%2 == 0 {// 忽略切片中值为偶数的元素continue loop}sum += sl[i]}println(sum) // 9
        }
        
      • 在这段代码中,我们定义了一个 label:loop,它标记的跳转目标恰恰就是我们的 for 循环。也就是说,我们在循环体中可以使用 continue+ loop label 的方式来实现循环体中断。
      • 通常我们在这样非嵌套循环的场景中会直接使用不带 label 的 continue 语句。
      • 带 label 的 continue 语句,通常出现于嵌套循环语句中,被用于跳转到外层循环并继续执行外层循环语句的下一个迭代:
        func main() {var sl = [][]int{{1, 34, 26, 35, 78},{3, 45, 13, 24, 99},{101, 13, 38, 7, 127},{54, 27, 40, 83, 81},}
        outerloop:for i := 0; i < len(sl); i++ {for j := 0; j < len(sl[i]); j++ {if sl[i][j] == 13 {fmt.Printf("found 13 at [%d, %d]\n", i, j)continue outerloop}}}
        }
        

break 语句的使用

  • 无论带不带 label,continue 语句的本质都是继续循环语句的执行。但日常编码中,我们还会遇到一些场景,在这些场景中,我们不仅要中断当前循环体迭代的进行,还要同时彻底跳出循环,终结整个循环语句的执行。面对这样的场景,continue 语句就不再适用了,Go 语言为我们提供了 break 语句来解决这个问题。
  • 和 continue 语句一样,Go 也 break 语句增加了对 label 的支持。而且,和 continue 语句一样,如果遇到嵌套循环,break 要想跳出外层循环,用不带 label 的 break 是不够,因为不带 label 的 break 仅能跳出其所在的最内层循环。要想实现外层循环的跳出,我们还需给 break 加上 label。

for 语句的常见“坑”与避坑方法

  • 问题一:循环变量的重用
    • for range 形式的循环语句,使用短变量声明的方式来声明循环变量,循环体将使用这些循环变量实现特定的逻辑,但在使用的时候,可能会发现循环变量的值与“预期”不符。
    • 有时候循环变量在 for range 语句中仅会被声明一次,且在每次迭代中都会被重用。
  • 问题二:参与循环的是 range 表达式的副本
    • 在 for range 语句中,range 后面接受的表达式的类型可以是数组、指向数组的指针、切片、字符串,还有 map 和 channel(需具有读权限)。
      func main() {var a = [5]int{1, 2, 3, 4, 5}var r [5]intfmt.Println("original a =", a)for i, v := range a {if i == 0 {a[1] = 12a[2] = 13}r[i] = v} fmt.Println("after for range loop, r =", r)fmt.Println("after for range loop, a =", a)
      }
      
      • 每次迭代的都是从数组 a 的值拷贝 a’ 中得到的元素。
      • a’是 Go 临时分配的连续字节序列,与 a 完全不是一块内存区域。
      • 因此无论 a 被如何修改,它参与循环的副本 a’依旧保持原值,因此 v 从 a’中取出的仍旧是 a 的原值,而不是修改后的值。
    • 那么应该如何解决这个问题,让输出结果符合我们的预期呢?
      • 大多数应用数组的场景我们都可以用切片替代:
        func main() {var a = [5]int{1, 2, 3, 4, 5}var r [5]intfmt.Println("original a =", a)for i, v := range a[:] {if i == 0 {a[1] = 12a[2] = 13}r[i] = v} fmt.Println("after for range loop, r =", r)fmt.Println("after for range loop, a =", a)
        }
        
      • 在 range 表达式中,我们用了 a[:]替代了原先的 a,也就是将数组 a 转换为一个切片,作为 range 表达式的循环对象。
      • 当进行 range 表达式复制时,我们实际上复制的是一个切片,也就是表示切片的结构体。表示切片副本的结构体中的 array,依旧指向原切片对应的底层数组,所以我们对切片副本的修改也都会反映到底层数组 a 上去。
      • 而 v 再从切片副本结构体中 array 指向的底层数组中,获取数组元素,也就得到了被修改后的元素值。
  • 问题三:遍历 map 中元素的随机性
    • 如果我们在循环的过程中,对 map 进行了修改,那么这样修改的结果是否会影响后续迭代呢?这个结果和我们遍历 map 一样,具有随机性。
    • 我们日常编码遇到遍历 map 的同时,还需要对 map 进行修改的场景的时候,要格外小心。

相关文章:

《Go 语言第一课》课程学习笔记(十一)

控制结构 if 的“快乐路径”原则 针对程序的分支结构&#xff0c;Go 提供了 if 和 switch-case 两种语句形式&#xff1b;而针对循环结构&#xff0c;Go 只保留了 for 这一种循环语句形式。 if 语句 if 语句是 Go 语言中提供的一种分支控制结构&#xff0c;它也是 Go 中最常…...

C++--完全背包问题

1.【模板】完全背包_牛客题霸_牛客网 你有一个背包&#xff0c;最多能容纳的体积是V。 现在有n种物品&#xff0c;每种物品有任意多个&#xff0c;第i种物品的体积为vivi​ ,价值为wiwi​。 &#xff08;1&#xff09;求这个背包至多能装多大价值的物品&#xff1f; &#xff0…...

显示本地 IP 地址和相应的 QR 码,方便用户共享和访问网络信息

这段代码使用了 wxPython、socket、qrcode 和 PIL&#xff08;Python Imaging Library&#xff09;模块来生成一个具有本地 IP 地址和相应 QR 码的窗口应用程序。 C:\pythoncode\new\showipgenqrcode.py 让我们逐行解释代码的功能&#xff1a; import wx&#xff1a;导入 wx…...

为什么建议同时学多门编程语言

晨读一本名叫《4点起床》的书&#xff0c;书中有一段描述与最近学习编制语言时自己的感受完全一致。算是一个小经验&#xff0c;分享给大家。 书中有一章的标题为《同时学六国语言记起来比较快》&#xff0c;其中有两段描述如下&#xff1a; 为什么我推荐大家同时学不同的语言…...

langchain agent

zero-shot-react-description 代码 from langchain.agents import initialize_agent from langchain.llms import OpenAI from langchain.tools import BaseTool import os os.environ[OPENAI_API_KEY]"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"# 搜索…...

Zabbix下载安装及SNMP Get使用

帮助文档&#xff1a;6. Zabbix Appliance 一、zabbix下载安装 1、获取Zabbix Appliance镜像 Download Zabbix appliance 2、使用该镜像创建虚拟机 3、打开虚拟机控制台自动安装&#xff0c;等待安装完成即可 默认配置 系统/数据库&#xff1a;root:zabbix Zabbix 前端&am…...

freee Programming Contest 2023(AtCoder Beginner Contest 310)

文章目录 A - Order Something Else&#xff08;模拟&#xff09;B - Strictly Superior&#xff08;模拟&#xff09;C - Reversible&#xff08;模拟&#xff09;D - Peaceful Teams(DFS状压)E - NAND repeatedly(普通dp)F - Make 10 Again&#xff08;状态压缩概率dp&#x…...

恒运资本:概念股是什么意思

概念股是指在特定的经济布景、方针环境、职业远景或社会热点等方面具有某种特别的发展远景和投资价值的股票。在投资者心目中&#xff0c;概念股的危险较大&#xff0c;可是或许带来高于商场平均水平的收益率。那么&#xff0c;概念股到底是什么意思&#xff1f;在本文中&#…...

十九、状态模式

一、什么是状态模式 状态&#xff08;State&#xff09;模式的定义&#xff1a;对有状态的对象&#xff0c;把复杂的“判断逻辑”提取到不同的状态对象中&#xff0c;允许状态对象在其内部状态发生改变时改变其行为。 状态模式包含以下主要角色&#xff1a; 环境类&#xff08…...

MySQL用navicat工具对表进行筛选查找

这个操作其实很简单&#xff0c;但是对于没操作的人来说&#xff0c;就是不会呀。所以小编出这一个详细图解&#xff0c;希望能够帮助到大家。话不多说看图。 第一步&#xff1a; 点进一张表&#xff0c;点击筛选。 第二步&#xff1a; 点击添加 第三步&#xff1a; 选择要…...

音视频 ffplay简单过滤器

视频旋转 ffplay -i test.mp4 -vf transpose1视频反转 ffplay test.mp4 -vf hflip ffplay test.mp4 -vf vflip视频旋转和反转 ffplay test.mp4 -vf hflip,transpose1音频变速播放 ffplay -i test.mp4 -af atempo2视频变速播放 ffplay -i test.mp4 -vf setptsPTS/2音视频同…...

索引 事务 存储引擎

################索引##################### 一、索引的概念 ●索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;。 ●使用索引后可以不用扫描全表来…...

MySQL— 基础语法大全及操作演示!!!(事务)

MySQL—— 基础语法大全及操作演示&#xff08;事务&#xff09; 六、事务6.1 事务简介6.2 事务操作6.2.1 未控制事务6.2.2 控制事务一6.2.3 控制事务二 6.3 事务四大特性6.4 并发事务问题6.5 事务隔离级别 MySQL— 基础语法大全及操作演示&#xff01;&#xff01;&#xff01…...

xsschallenge1~13通关详细教程

文章目录 XSS 挑战靶场通关level1level2level3level4level5level6level7level8level9level10level11level12level13 XSS 挑战靶场通关 level1 通过观察发现这个用户信息可以修改 那么我们直接输入攻击代码 <script>alert(/wuhu/)</script>弹框如下&#xff1a; …...

考生作弊行为分析算法

考生作弊行为分析系统利用pythonyolo系列网络模型算法框架&#xff0c;考生作弊行为分析算法利用图像处理和智能算法对考生的行为进行分析和识别&#xff0c;经过算法服务器的复杂计算和逻辑判断&#xff0c;算法将根据考生行为的特征和规律&#xff0c;判定是否存在作弊行为。…...

Python 操作 Redis 数据库介绍

Redis 作为常用的 NoSql 数据库&#xff0c;主要用于缓存数据&#xff0c;提高数据读取效率&#xff0c;那在 Python 中应该如果连接和操作 Redis 呢&#xff1f;今天就为大概简单介绍下&#xff0c;在 Python 中操作 Redis 常用命令。 安装 redis 首先还是需要先安装 redis …...

十年JAVA搬砖路——软件工程概述

软件工程是一门关注软件开发过程的学科&#xff0c;它涉及到软件的设计、开发、测试、部署和维护等方面。软件工程的目标是通过系统化的方法和工具&#xff0c;以确保软件项目能够按时、按预算和按要求完成。 • 软件工程的7个基本概念&#xff1a; 软件生命周期&#xff1a;软…...

前后端项目部署上线详细笔记

部署 参考文章&#xff1a;如何部署网站&#xff1f;来比比谁的方法多 - 哔哩哔哩大家好&#xff0c;我是鱼皮&#xff0c;不知道朋友们有没有试着部署过自己开发的网站呢&#xff1f;其实部署网站非常简单&#xff0c;而且有非常多的花样。这篇文章就给大家分享几种主流的前端…...

Android 蓝牙开发( 二 )

前言 上一篇文章给大家分享了Android蓝牙的基础知识和基础用法&#xff0c;不过上一篇都是一些零散碎片化的程序&#xff0c;这一篇给大家分享Android蓝牙开发实战项目的初步使用 效果演示 : Android蓝牙搜索&#xff0c;配对&#xff0c;连接&#xff0c;通信 Android蓝牙实…...

C#调用barTender打印标签示例

使用的电脑需要先安装BarTender 我封装成一个类 using System; using System.Windows.Forms;namespace FT_Tools {public class SysContext{public static BarTender.Application btapp new BarTender.Application();public static BarTender.Format btFormat;public void Q…...

Spring——Spring读取文件

文章目录 1.通过 value 读取比较简单的配置信息2.通过ConfigurationProperties读取并与 bean 绑定3.通过ConfigurationProperties读取并校验4. PropertySource 读取指定 properties 文件5.题外话:Spring加载配置文件的优先级 很多时候我们需要将一些常用的配置信息比如阿里云os…...

这是一条求助贴(postman测试的时候一直是404)

看到这个问题是404的时候总感觉不该求助大家&#xff0c;404多常见一看就是简单的路径问题&#xff0c;我的好像不是&#xff0c;我把我的问题奉上。 首先我先给出我的url http://10.3.22.195:8080/escloud/rest/escloud_contentws/permissionStatistics/jc-haojl/sz 这是我…...

信号完整性分析基础知识之有损传输线、上升时间衰减和材料特性(四):有损传输线建模

传输线中信号衰减的两个损耗过程是通过信号和返回路径导体的串联电阻以及通过有损耗介电材料的分流电阻。这两个电阻器的电阻都与频率相关。 值得注意的是&#xff0c;理想电阻器的电阻随频率恒定。我们已经证明&#xff0c;在理想的有损传输线中&#xff0c;用于描述损耗的两个…...

elk日志收集系统

目录 前言 一、概述 二、案例 &#xff08;一&#xff09;、环境配置 安装node1与node2节点的elasticsearch node1的elasticsearch-head插件 &#xff08;二&#xff09;、node1服务器安装logstash 测试1&#xff1a; 标准输入与输出 测试2&#xff1a;使用rubydebug解…...

perl 语言中 AUTOLOAD 的用法

这里的 AUTOLOAD可以理解为自动加载。具体来说就是&#xff0c;在正常情况下&#xff0c;我们不能调用一个尚未定义的函数&#xff08;子例程&#xff09;。不过&#xff0c;如果在未定义函数的包中有一个名为 AUTOLOAD的函数&#xff0c;那么对未定义函数的调用都会路由至这个…...

服务器放在香港好用吗?

​  相较于国内服务器&#xff0c;将网站托管在香港服务器上最直观的好处是备案层面上的。香港服务器上的网站无需备案&#xff0c;因此更无备案时限&#xff0c;购买之后即可使用。 带宽优势 香港服务器的带宽一般分为香港本地带宽和国际带宽、直连中国骨干网 CN2三种。香港…...

C++设计模式_01_设计模式简介(多态带来的便利;软件设计的目标:复用)

文章目录 本栏简介1. 什么是设计模式2. GOF 设计模式3. 从面向对象谈起4. 深入理解面向对象5. 软件设计固有的复杂性5.1 软件设计复杂性的根本原因5.2 如何解决复杂性 ? 6. 结构化 VS. 面向对象6.1 同一需求的分解写法6.1.1 Shape1.h6.1.2 MainForm1.cpp 6.2 同一需求的抽象的…...

Docker技术--WordPress博客系统部署初体验

如果使用的是传统的项目部署方式,你要部署WordPress博客系统,那么你需要装备一下的环境,才可以部署使用。 -1:操作系统linux -2:PHP5.6或者是更高版本环境 -3:MySQL数据环境 -4:Apache环境 但是如果使用Docker技术,那么就只需要进行如下的几行简单的指令: docker run …...

提高代码可读性和可维护性的命名建议

当进行接口自动化测试时&#xff0c;良好的命名可以提高代码的可读性和可维护性。以下是一些常用的命名建议&#xff1a; 变量和函数命名&#xff1a; 使用具有描述性的名称&#xff0c;清晰地表达变量或函数的用途和含义。使用小写字母和下划线来分隔单词&#xff0c;例如 log…...

Docker基础入门:Docker网络与微服务项目发布

Docker基础入门&#xff1a;Docker网络与微服务项目发布 一、前言二、Docker0理解2.1 ip a查看当前网络环境2.2 实战--启动一个tomact01容器&#xff08;查看网络环境&#xff09;2.3 实战--启动一个tomact02容器&#xff08;查看网络环境&#xff09;2.4 容器与容器之间的通信…...