【Go语言精进之路】构建高效Go程序:了解string实现原理并高效使用

news2024/11/25 4:57:01

在这里插入图片描述

🔥 个人主页:空白诗
🔥 热门专栏:【Go语言精进之路】

在这里插入图片描述

文章目录

    • 引言
    • 一、Go语言的字符串类型
      • 1.1 字符串的定义
      • 1.2 字符串的零值可用
      • 1.3 字符串的不可变性
      • 1.4 字符串的拼接
      • 1.5 字符串的常用方法
      • 1.6 实际使用示例
    • 二、字符串的内部表示
      • 2.1 字符串的底层结构
      • 2.2 字符串与字节切片的关系
        • 字符串转换为字节切片
        • 字节切片转换为字符串
      • 2.3 字符串的编码
        • 遍历字符串
      • 2.4 不可变性的实现
      • 2.5 字符串的内存管理
      • 2.6 字符串池
    • 三、字符串的高效构造
      • 3.1 使用 strings.Builder
        • 示例:
        • 性能优势:
      • 3.2 使用字节缓冲区
        • 示例:
        • 性能优势:
      • 3.3 预分配切片
        • 示例:
        • 性能优势:
      • 3.4 使用 strings.Join
        • 示例:
        • 性能优势:
      • 3.5 选择合适的方法
    • 四、字符串相关的高效转换
      • 4.1 字符串与数字的转换
        • 字符串转换为整数
        • 整数转换为字符串
      • 4.2 字符串与字节切片的转换
        • 字符串转换为字节切片
        • 字节切片转换为字符串
      • 4.3 字符串与字符(rune)的转换
        • 字符串转换为字符切片
        • 字符切片转换为字符串
      • 4.4 字符串与其他数据类型的转换
        • 布尔值转换
        • 浮点数转换
    • 总结

在这里插入图片描述

引言

在Go语言中,字符串是一个重要且经常使用的数据类型。无论是处理文本数据、构建复杂字符串,还是在不同数据类型之间进行转换,高效的字符串操作都对程序性能至关重要。本篇文章将深入探讨Go语言中的字符串类型,从基本的字符串定义和操作,到字符串的内部表示,再到高效的字符串构造和转换方法,通过全面的讲解和实例代码,帮助读者更好地理解和使用Go语言的字符串功能。

一、Go语言的字符串类型

在这里插入图片描述

在Go语言中,字符串类型是非常重要且经常使用的数据类型。字符串用于存储字符序列,在Go语言中,它们是不可变的。这意味着一旦创建了字符串,它的内容是无法更改的。接下来,我们将深入了解Go语言的字符串类型,包括它的定义、操作、常用方法以及一些实际的使用示例。

1.1 字符串的定义

在Go语言中,字符串使用双引号 " 包裹起来。例如:

package main

import "fmt"

func main() {
    var str1 string = "Hello, World!"
    str2 := "Go语言"
    fmt.Println(str1)
    fmt.Println(str2)
}

上述代码定义了两个字符串变量 str1str2,并打印它们的值。Go语言支持UTF-8编码,这意味着字符串可以包含多种语言的字符。

1.2 字符串的零值可用

在Go语言中,字符串类型的零值是一个空字符串,也就是 ""。这意味着当你声明一个字符串变量但未对其进行初始化时,它的默认值是空字符串。这种特性可以帮助我们在编写代码时避免出现空指针异常的问题。

package main

import "fmt"

func main() {
    var str string
    fmt.Println("字符串的零值:", str) // 输出:字符串的零值:
    fmt.Println("字符串是否为空:", str == "") // 输出:字符串是否为空: true
}

在这个例子中,变量 str 声明后未被初始化,因此它的值是空字符串。我们可以通过比较操作 str == "" 来确认这一点。

1.3 字符串的不可变性

Go语言中的字符串是不可变的,这意味着你不能直接修改字符串中的某个字符。例如,以下代码是非法的:

package main

func main() {
    str := "Hello"
    str[0] = 'h' // 编译错误:cannot assign to str[0]
}

如果需要修改字符串,可以创建一个新的字符串。例如:

package main

import "fmt"

func main() {
    str := "Hello"
    newStr := "h" + str[1:]
    fmt.Println(newStr) // 输出:hello
}

1.4 字符串的拼接

Go语言提供了多种方法来拼接字符串。最常用的方法是使用 + 操作符:

package main

import "fmt"

func main() {
    str1 := "Hello"
    str2 := "World"
    result := str1 + ", " + str2 + "!"
    fmt.Println(result) // 输出:Hello, World!
}

对于大量字符串的拼接,推荐使用 strings.Builder,因为它更加高效:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var builder strings.Builder
    builder.WriteString("Hello")
    builder.WriteString(", ")
    builder.WriteString("World")
    builder.WriteString("!")
    result := builder.String()
    fmt.Println(result) // 输出:Hello, World!
}

1.5 字符串的常用方法

Go语言的 strings 包提供了许多用于操作字符串的函数。以下是一些常用方法:

  • len(s):返回字符串的长度(字节数)。
  • strings.Split(s, sep):将字符串按指定分隔符拆分成子串数组。
  • strings.Join(a, sep):将字符串数组按指定分隔符合并成一个字符串。
  • strings.Contains(s, substr):判断字符串是否包含子串。
  • strings.ToUpper(s)strings.ToLower(s):将字符串转换为大写或小写。

示例:

package main

import (
    "fmt"
    "strings"
)

func main() {
    str := "Hello, Go语言!"
    
    fmt.Println("长度:", len(str)) // 输出:长度: 14

    parts := strings.Split(str, ", ")
    fmt.Println("拆分:", parts) // 输出:拆分: [Hello Go语言!]

    joined := strings.Join(parts, " - ")
    fmt.Println("合并:", joined) // 输出:合并: Hello - Go语言!

    fmt.Println("包含 'Go':", strings.Contains(str, "Go")) // 输出:包含 'Go': true

    fmt.Println("大写:", strings.ToUpper(str)) // 输出:大写: HELLO, GO语言!
    fmt.Println("小写:", strings.ToLower(str)) // 输出:小写: hello, go语言!
}

1.6 实际使用示例

以下是一个实际使用字符串的示例:检查一个字符串是否是回文(即正读和反读都一样)。

package main

import (
    "fmt"
    "strings"
)

func isPalindrome(s string) bool {
    s = strings.ToLower(s)
    s = strings.ReplaceAll(s, " ", "")
    s = strings.ReplaceAll(s, ",", "")
    s = strings.ReplaceAll(s, "!", "")
    n := len(s)
    for i := 0; i < n/2; i++ {
        if s[i] != s[n-1-i] {
            return false
        }
    }
    return true
}

func main() {
    str := "A man, a plan, a canal, Panama!"
    fmt.Println("是否是回文:", isPalindrome(str)) // 输出:是否是回文: true
}

在这个示例中,我们定义了一个函数 isPalindrome 来检查字符串是否是回文。我们使用 strings 包提供的方法来处理字符串并进行检查。

通过上述内容,我们可以了解到Go语言中字符串类型的基本概念和常用操作方法。字符串在编程中无处不在,掌握其使用方法对于Go语言开发非常重要。


二、字符串的内部表示

在这里插入图片描述

在Go语言中,字符串的内部表示方式决定了它的高效性和灵活性。了解字符串的内部结构对于理解其性能特征和行为至关重要。本部分将详细介绍Go语言中字符串的内部表示。

2.1 字符串的底层结构

在Go语言中,字符串是一个只读的字节切片。实际上,字符串是一个结构体,它包含一个指向底层字节数组的指针和一个长度字段。Go语言的字符串定义如下:

type string struct {
    data uintptr
    len  int
}

这里,data 是一个指向实际存储字符串内容的字节数组的指针,而 len 则是字符串的长度。这个设计使得字符串可以高效地进行长度计算和内容访问。

2.2 字符串与字节切片的关系

由于字符串在内部是一个字节数组,因此可以方便地与字节切片进行互相转换。

字符串转换为字节切片

将字符串转换为字节切片是一个常见的操作,可以使用标准库中的 []byte 类型转换:

package main

import "fmt"

func main() {
	str := "Hello, Go语言!"
	byteSlice := []byte(str)
	fmt.Println(byteSlice) // 输出:[72 101 108 108 111 44 32 71 111 232 175 173 232 168 128 33]
}
字节切片转换为字符串

将字节切片转换为字符串也非常简单,可以直接使用 string 类型转换:

package main

import "fmt"

func main() {
	byteSlice := []byte{72, 101, 108, 108, 111, 44, 32, 71, 111, 232, 175, 173, 232, 168, 128, 33}
	str := string(byteSlice)
	fmt.Println(str) // 输出:Hello, Go语言!
}

2.3 字符串的编码

Go语言的字符串默认使用UTF-8编码,这使得字符串可以方便地处理多种语言的字符。UTF-8是一种变长编码,ASCII字符使用一个字节,而其他字符使用两个到四个字节不等。

遍历字符串

遍历字符串时,需要注意字符的编码。直接遍历字符串实际上是遍历其字节,这可能导致非ASCII字符被错误处理。可以使用 for range 循环来正确遍历UTF-8编码的字符串:

package main

import "fmt"

func main() {
    str := "Hello, Go语言!"
    for i, r := range str {
        fmt.Printf("字符 %c 的位置 %d\n", r, i)
    }
}

在这个例子中,for range 循环能够正确处理多字节的UTF-8字符,并返回字符的索引和Unicode码点。

2.4 不可变性的实现

字符串的不可变性是通过不提供直接修改字符串内容的方法来实现的。一旦字符串被创建,无法通过其指针或其他方式修改其内容。这种设计在提升字符串操作的安全性和并发性方面有显著优势,因为无需担心多个线程对同一个字符串进行修改。

如果需要修改字符串,可以创建一个新的字符串。例如:

package main

import "fmt"

func main() {
    str := "Hello"
    newStr := "h" + str[1:]
    fmt.Println(newStr) // 输出:hello
}

2.5 字符串的内存管理

由于字符串是不可变的,Go语言在处理字符串时尽量避免不必要的内存分配。对于短小的字符串,Go语言的运行时会优化其内存分配。例如,对于长度为零的字符串,Go语言会将其指针指向一个共享的空字符串,而不是为每个空字符串分配单独的内存。

2.6 字符串池

Go语言在编译时会将相同的字符串常量合并到一个字符串池中。这意味着在程序的不同部分使用相同的字符串常量时,它们实际上指向的是内存中的同一个位置。这样可以减少内存使用和提高字符串比较的效率。

例如:

package main

import "fmt"

func main() {
    str1 := "Hello, World!"
    str2 := "Hello, World!"
    fmt.Println(&str1 == &str2) // 输出:true
}

在这个例子中,str1str2 实际上指向同一个字符串常量。

通过了解Go语言中字符串的内部表示,我们可以更好地理解字符串操作的性能和行为,从而在开发中更高效地使用字符串。


三、字符串的高效构造

在这里插入图片描述

在Go语言中,高效地构造字符串对于提升程序性能至关重要。特别是在需要频繁拼接或处理大量字符串的场景下,合理的字符串构造方式可以显著减少内存分配和提升执行效率。本部分将介绍几种常用的高效构造字符串的方法,包括使用 strings.Builder、字节缓冲区和预分配切片等技术。

3.1 使用 strings.Builder

strings.Builder 是Go语言标准库中的一种高效构造字符串的方法。它通过内部维护一个可变的字节缓冲区,避免了频繁的内存分配和复制操作。

示例:
package main

import (
    "fmt"
    "strings"
)

func main() {
    var builder strings.Builder
    builder.WriteString("Hello")
    builder.WriteString(", ")
    builder.WriteString("Go语言")
    builder.WriteString("!")
    result := builder.String()
    fmt.Println(result) // 输出:Hello, Go语言!
}
性能优势:
  • 减少内存分配strings.Builder 通过内部的缓冲区来管理字节数组,避免了每次拼接操作时创建新的字符串。
  • 高效拼接:多次调用 WriteString 方法可以累积字符串内容,最终通过 String 方法生成最终字符串。

3.2 使用字节缓冲区

bytes.Buffer 是另一种高效构造字符串的工具,特别适用于需要处理二进制数据和字符串混合的场景。

示例:
package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer
    buffer.WriteString("Hello")
    buffer.WriteString(", ")
    buffer.WriteString("Go语言")
    buffer.WriteString("!")
    result := buffer.String()
    fmt.Println(result) // 输出:Hello, Go语言!
}
性能优势:
  • 灵活性bytes.Buffer 不仅可以处理字符串,还可以处理其他类型的二进制数据。
  • 线程安全:与 strings.Builder 类似,bytes.Buffer 也能有效地减少内存分配和复制操作。

3.3 预分配切片

在知道最终字符串长度的情况下,可以通过预分配字节切片来提高拼接效率。这种方法适用于构造定长或接近定长的字符串。

示例:
package main

import "fmt"

func main() {
    parts := []string{"Hello", ", ", "Go语言", "!"}
    totalLength := 0
    for _, part := range parts {
        totalLength += len(part)
    }
    
    buf := make([]byte, totalLength)
    pos := 0
    for _, part := range parts {
        copy(buf[pos:], part)
        pos += len(part)
    }
    
    result := string(buf)
    fmt.Println(result) // 输出:Hello, Go语言!
}
性能优势:
  • 减少内存分配:通过一次性分配足够的内存来存储所有字符串部分,避免了多次内存分配。
  • 高效拼接:使用 copy 函数直接将字符串内容复制到预分配的字节切片中。

3.4 使用 strings.Join

对于已知的多个字符串片段,可以使用 strings.Join 方法一次性拼接所有字符串。这种方法适用于字符串列表已知且固定的情况。

示例:
package main

import (
    "fmt"
    "strings"
)

func main() {
    parts := []string{"Hello", ", ", "Go语言", "!"}
    result := strings.Join(parts, "")
    fmt.Println(result) // 输出:Hello, Go语言!
}
性能优势:
  • 简单高效strings.Join 方法内部会计算总长度并一次性分配内存,从而高效地拼接字符串。
  • 简洁代码:使用 strings.Join 可以使代码更加简洁明了。

3.5 选择合适的方法

在实际开发中,选择合适的字符串构造方法需要根据具体场景和需求来确定:

  • 大量拼接strings.Builder 是通用且高效的选择。
  • 二进制数据处理bytes.Buffer 更适合处理混合数据。
  • 已知长度:预分配切片可以提供最佳性能。
  • 固定片段拼接strings.Join 简洁且高效。

通过合理选择和使用这些方法,我们可以在不同场景下高效地构造字符串,从而提升Go语言程序的整体性能。

四、字符串相关的高效转换

在这里插入图片描述

在Go语言中,字符串与其他数据类型之间的转换是常见的操作。高效的转换方法不仅能够提升程序性能,还能减少不必要的内存分配和数据复制。本部分将介绍几种常见的字符串转换操作,包括字符串与数字、字符串与字节切片、字符串与字符(rune)的高效转换方法。

4.1 字符串与数字的转换

在许多应用场景中,我们需要在字符串和数字之间进行转换。Go语言标准库提供了 strconv 包来高效地处理这些转换。

字符串转换为整数

使用 strconv.Atoistrconv.ParseInt 将字符串转换为整数:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := "12345"
    num, err := strconv.Atoi(str)
    if err != nil {
        fmt.Println("转换错误:", err)
    } else {
        fmt.Println("转换后的整数:", num) // 输出:转换后的整数: 12345
    }
}
整数转换为字符串

使用 strconv.Itoastrconv.FormatInt 将整数转换为字符串:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    num := 12345
    str := strconv.Itoa(num)
    fmt.Println("转换后的字符串:", str) // 输出:转换后的字符串: 12345
}

4.2 字符串与字节切片的转换

字符串与字节切片之间的转换在处理二进制数据时非常常见。Go语言提供了高效的转换方式。

字符串转换为字节切片

使用类型转换 []byte 可以高效地将字符串转换为字节切片:

package main

import "fmt"

func main() {
    str := "Hello, Go语言!"
    byteSlice := []byte(str)
    fmt.Println("字节切片:", byteSlice) // 输出:字节切片: [72 101 108 108 111 44 32 71 111 232 175 173 232 168 128 33]
}
字节切片转换为字符串

使用类型转换 string 可以高效地将字节切片转换为字符串:

package main

import "fmt"

func main() {
    byteSlice := []byte{72, 101, 108, 108, 111, 44, 32, 71, 111, 232, 175, 173, 232, 168, 128, 33}
    str := string(byteSlice)
    fmt.Println("字符串:", str) // 输出:Hello, Go语言!
}

4.3 字符串与字符(rune)的转换

在处理多语言文本时,经常需要将字符串分割为字符 (rune) 进行处理。Go语言中的 rune 类型表示一个Unicode码点。

字符串转换为字符切片

使用 for range 循环可以高效地将字符串分割为字符切片:

package main

import "fmt"

func main() {
	str := "Hello, Go语言!"
	var runes []rune
	for _, r := range str {
		runes = append(runes, r)
	}
	fmt.Println("字符切片:", runes) // 输出:字符切片: [72 101 108 108 111 44 32 71 111 35821 35328 33]
}
字符切片转换为字符串

可以使用 string 函数将字符切片转换为字符串:

package main

import "fmt"

func main() {
    runes := []rune{72, 101, 108, 108, 111, 44, 32, 71, 111, 35821, 35328, 33}
    str := string(runes)
    fmt.Println("字符串:", str) // 输出:Hello, Go语言!
}

4.4 字符串与其他数据类型的转换

布尔值转换

使用 strconv.ParseBool 将字符串转换为布尔值:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := "true"
    boolVal, err := strconv.ParseBool(str)
    if err != nil {
        fmt.Println("转换错误:", err)
    } else {
        fmt.Println("转换后的布尔值:", boolVal) // 输出:转换后的布尔值: true
    }
}

使用 strconv.FormatBool 将布尔值转换为字符串:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    boolVal := true
    str := strconv.FormatBool(boolVal)
    fmt.Println("转换后的字符串:", str) // 输出:转换后的字符串: true
}
浮点数转换

使用 strconv.ParseFloat 将字符串转换为浮点数:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := "123.45"
    floatVal, err := strconv.ParseFloat(str, 64)
    if err != nil {
        fmt.Println("转换错误:", err)
    } else {
        fmt.Println("转换后的浮点数:", floatVal) // 输出:转换后的浮点数: 123.45
    }
}

使用 strconv.FormatFloat 将浮点数转换为字符串:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    floatVal := 123.45
    str := strconv.FormatFloat(floatVal, 'f', 2, 64)
    fmt.Println("转换后的字符串:", str) // 输出:转换后的字符串: 123.45
}

通过了解和使用这些高效的字符串转换方法,我们可以在Go语言中更好地处理字符串与其他数据类型之间的转换,从而提升代码的性能和可读性。

总结

本文详细介绍了Go语言中字符串的各个方面。首先,我们讨论了字符串的基本定义和特性,包括字符串的零值、不可变性和常见操作。接着,我们深入探讨了字符串的内部表示,解释了字符串在内存中的结构和与字节切片的关系。随后,我们介绍了高效构造字符串的方法,包括使用 strings.Builder、字节缓冲区和预分配切片等技术。最后,我们展示了字符串与其他数据类型之间的高效转换方法。通过这些内容,希望读者能够掌握高效处理Go语言字符串的技巧,从而编写出性能更优的程序。

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

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

相关文章

HTML学习和JAVAScript学习

HTML 标签 <!DOCTYPE html> <!-- 文档类型为html --> <html lang"en"> <head><meta charset"UTF-8"> <!-- 使用字符集UTF-8 --> <!-- 设置浏览器兼容性 --><meta name"viewpo…

TCP/IP协议简要介绍

TCP/IP for IP version 4&#xff08;IPv4&#xff09;是一种网络协议&#xff0c;Microsoft Windows使用该协议通过internet与其他计算机进行通信。理想情况下&#xff0c;只要基于Windows的计算机通过网络进行通信&#xff0c;就会使用TCP/IP。 本文介绍TCP/IP协议的组成、协…

vue2双层循环生成动态ref,并跳转到组件内的指定位置

话不用多说,先上一个视频,看看是不是你们需要的效果 vue2双层循环生成动态ref,并跳转到组件内的指定位置 <div class"menu-content" ref"menu"><el-collapse v-model"activeNames"><el-collapse-item style"padding: 10px;…

Java每日作业day6.18

ok了家人们今天我们继续学习方法的更多使用&#xff0c;闲话少叙&#xff0c;我们来看今天学了什么 1.重载 在同一个类中&#xff0c;可不可以存在同名的方法&#xff1f;重载:在同一个类中&#xff0c;定义了多个同名的方法&#xff0c;但每个方法具有不同的参数类型或参数个…

传统车牌识别

主要参考&#xff1a;https://blog.csdn.net/qq_40784418/article/details/105586644 其它介绍&#xff1a; https://blog.csdn.net/great_yzl/article/details/120127962 https://blog.csdn.net/onepunch_k/article/details/115480904 cv2.matchTemplate https://docs.ope…

三星SAINT-D技术引领HBM内存堆叠革命

三星电子即将在今年推出一项革命性技术&#xff0c;允许在CPU或GPU上堆叠高带宽内存&#xff08;HBM&#xff09;&#xff0c;根据韩国经济日报的报道&#xff0c;这一消息在圣何塞举办的三星晶圆代工论坛2024上公布&#xff0c;并得到业内消息人士证实。这项3D封装技术为2025年…

ESP32蓝牙BLE连接米家温湿度计

ESP32蓝牙BLE连接米家温湿度计 文章目录 ESP32蓝牙BLE连接米家温湿度计简介需要准备的东西软件调试代码实现修改查找的名称 修改需要连接的服务和属性添加解析数据的代码 上电演示提示 简介 最近在学习低功耗蓝牙BLE(Bluetooth Low Energy)&#xff0c;刚好手里有个米家蓝牙温…

总结一下 C# 如何自定义特性 Attribute 并进行应用

前言 Attribute&#xff08;特性&#xff09;是一种用于为程序元素&#xff08;如类、方法、属性等&#xff09;提供元数据信息的方法。 特性是一种声明式的信息&#xff0c;附加到程序元素上&#xff0c;提供额外的数据用于描述和控制这些元素的行为。 在编译和运行时&…

WMS系统调拨盘点功能:优化仓储管理效率

一、调拨功能概述 WMS系统的调拨功能是指仓库内部或者不同仓库之间对商品进行转移的过程。调拨的目的在于平衡库存、优化存储空间和提高物流效率。调拨功能主要包括以下几个方面&#xff1a; 1. 调拨申请&#xff1a;根据业务需求&#xff0c;仓库管理员可以发起调拨申请&…

软件设计不是CRUD(23):在流式数据处理系统中进行业务抽象落地——详细编码

&#xff08;接上文《软件设计不是CRUD&#xff08;22&#xff09;&#xff1a;在流式数据处理系统中进行业务抽象落地——设计思考》&#xff09; 4、详细设计 项目开发初期&#xff0c;有两种测速雷达和对应的摄像头需要接入&#xff0c;分别是STC500型测速雷达和TTS400型测…

《UNIX环境高级编程》第三版(电子工业出版社出品)——两年磨一剑的匠心译作

历时两年&#xff0c;《UNIX环境高级编程》的翻译工作终于落下帷幕。这一路走来&#xff0c;真可谓是如鱼饮水&#xff0c;冷暖自知。还记得最初看到招募译者消息的那一刻&#xff0c;内心的激动难以言表。我毫不犹豫地报名&#xff0c;而后经历了试译、海选等激烈的角逐&#…

TestProject Python SDK入门

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。​编辑https://…

怎么提取视频中的音频?别错过这6个音频提取方法了!(全新)

您是否曾经发现过一个音乐很棒的视频&#xff0c;并想从视频中提取音频&#xff1f;如今&#xff0c;关于提取mp4视频中的音频需求越来越常见。例如&#xff0c;您可能想从mp4格式的电影中提取音频&#xff0c;将音乐用作手机铃声&#xff0c;或在自己的视频项目中使用视频中的…

C#唯一进程的处理Winform/WPF

C#唯一进程的处理 1.使用进程&#xff08;Process&#xff09;判断winformWPF执行效果&#xff1a; 2.使用互斥体&#xff08;Metux&#xff09;实现winformWPF实现效果&#xff1a; 在C#客户端&#xff08;Winform/WPF&#xff09;开发过程中&#xff0c;有的情况需要确保程序…

零基础入门学用Arduino 第四部分(一)

重要的内容写在前面&#xff1a; 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。个人把这个教程学完之后&#xff0c;整体感觉是很好的&#xff0c;如果有条件的可以先学习一些相关课程&#xff0c;学起来会更加轻松&#xff0c;相关课程有数字电路…

Microsoft Visual C++ Redistributable 【安装包】【高速下载】

方法1、可以从官方下载&#xff0c;如下图 方法2 已经下载好并且已经整理好了2008--2022的所有版本点击下方链接即可高速下载 如果是win7-win8-win10-win11直接可以下载2015--2022版本&#xff0c;xp需要下载2015之前的 点击链接Microsoft Visual C Redistributable官方版本…

茶艺师服务师傅小程序APP源码(APP+小程序+公众号+H5)

&#x1f375;茶艺师服务小程序&#xff1a;品味生活的茶艺新体验&#x1f331; &#x1f33f;一、引言&#xff1a;茶艺师服务小程序&#xff0c;让生活更有味 在繁忙的生活中&#xff0c;品一杯香茗&#xff0c;感受茶文化的韵味&#xff0c;是许多人向往的休闲方式。然而&…

Android开发系列(四)Jetpack Compose之Button

在Jetpack Compose中&#xff0c;Button是一个常用的用户界面组件&#xff0c;用于执行某些操作或触发某些事件。Button控件是可触摸的&#xff0c;并且通常会显示一个文本或图标来表示其功能。 要在Jetpack Compose中创建一个Button&#xff0c;可以使用Button()函数&#xf…

C#——正则表达式详情

正则表达式 正则表达式: 列如判断一个字符串是不是手机号&#xff0c;或者密码是否包含大小写数字等这些要求&#xff0c;可以把这些条件写成一个表达式 创建正则表达式 string s1 "1234adsab1KHGFJD"; // 创建正则时需要在字符串前面加上 Regex r new Regex(&q…

序列化与反序列化漏洞实例

实验环境&#xff1a; 本次的序列化与反序列化漏洞为2021年强网杯上的一道比赛题目&#xff0c;我使用phpstudy集成环境将其测试环境搭建在了本地&#xff0c;如下。涉及的几个页面php为&#xff1a; index.php function.php myclass.php index.php : <?php // inde…