golang--数据类型与存储

在 Go 语言中,理解值类型(value types)和引用类型(reference types)的区别对于编写高效、正确的代码至关重要。以下是主要的区别点和需要注意的特殊情况:

一、值类型(Value Types)

包含的类型

  • 基本数据类型(bool, int, float, complex, string 等)
  • 数组(array
  • 结构体(struct

核心特点:

1. 直接存储值

a := 42
b := a  // 创建 a 的副本(值复制)
b = 10  // 修改 b 不影响 a
fmt.Println(a) // 42

2. 传参时复制整个值

func modify(arr [3]int) {arr[0] = 100
}
original := [3]int{1, 2, 3}
modify(original)
fmt.Println(original) // [1 2 3](未改变)

内存存储

通常分配在栈上(小对象),但可能逃逸到堆(如函数返回局部变量地址时)。

类型存储方式大小特点
bool直接存储(true=1,false=0)1字节零值=false
整数类型直接存储二进制值int8/16/32/64支持位操作
浮点数IEEE-754 标准float32(4B)/64(8B)精确计算需用 math/big
complex实部+虚部存储8/16字节complex128 精度更高
array连续内存块len*元素大小长度固定,类型签名包含长度

示例:

// 数组存储示例
arr := [3]int{1, 2, 3}
// 内存布局:[0x01, 0x00, 0x00, 0x00, 0x02, ...] (小端序)

3. 内存分配在栈上(小对象)

  • 小对象(如结构体)通常在栈上分配,速度更快

4. string 的特殊性

  • 共享只读
   s1 := "hello"s2 := s1 // 虽然 string 是值类型,但底层共享只读字节数组// 修改会触发新内存分配(不可变性)
  • 底层字节数组不可变:
s := "hello"
// s[0] = 'H' // 编译错误(禁止修改)
s2 := s          // 复制描述符(8+8=16字节),共享底层数据
s3 := s + "world" // 新建底层数组(复制+追加)
  • 子串零成本​​:截取子串不需要复制数据
    截取子字符串(如s[i:j])时,会创建一个新的字符串头,其中Data指向原字符串的相应位置(即原起始地址加上偏移量i),长度设置为j-i。因此,子字符串和原字符串共享一部分底层数组。

5. 比较支持

type Point struct{ X, Y int }
p1 := Point{1, 2}
p2 := Point{1, 2}
fmt.Println(p1 == p2) // true(可比较)

String

Unicode库,判断字符的类型


其中 v 代表字符):
判断是否为字母: unicode.IsLetter(v)
判断是否为十进制数字: unicode.IsDigit(v)
判断是否为数字: unicode.IsNumber(v)
判断是否为空白符号: unicode.IsSpace(v)
判断是否为Unicode标点字符 :unicode.IsPunct(v)

取出一个字符串中的字符串和数值字符串
得到map[ddgm:[495 468] fdfsf:[123.4 1.2 11] dg:[49151]]

str:="fdfsf,123.4,1.2,11,dg,49151,ddgm,495,468"
istMap :=  make(map[string][]string)
start := 0var key stringvar value []stringvar tmp stringvar tmpArr []stringfor index, v := range instruction {if string(v) == "," && index != len(instruction)-1 && unicode.IsLetter(rune(instruction[index+1])) { //标点和结束tmp = instruction[start:index]tmpArr = strings.Split(tmp, ",")key = tmpArr[0]value = tmpArr[1:]istMap[key] = valuestart = index + 1}if index == len(str)-1 { //数值tmp = str[start : index+1]tmpArr = strings.Split(tmp, ",")key = tmpArr[0]value = tmpArr[1:]istMap[key] = valuestart = index + 1}}

只读共享

	s := "abcdef"s1 := sfmt.Printf("s指针地址: %p\n", &s)fmt.Printf("s1指针地址: %p\n", &s1)fmt.Printf("s底层数据地址: %p\n", unsafe.StringData(s))fmt.Printf("s1底层数据地址: %p\n", unsafe.StringData(s1))//(只读共享)// 修改操作会触发新分配s1 += " world"fmt.Printf("s指针地址: %p\n", &s)fmt.Printf("s1指针地址: %p\n", &s1)fmt.Printf("s底层数据地址: %p\n", unsafe.StringData(s))fmt.Printf("s1底层数据地址: %p\n", unsafe.StringData(s1))
/*
s指针地址: 0xc00023aab0
s1指针地址: 0xc00023aac0
s底层数据地址: 0x184b115
s1底层数据地址: 0x184b115
s指针地址: 0xc00023aab0
s1指针地址: 0xc00023aac0
s底层数据地址: 0x184b115
s1底层数据地址: 0xc000213120
*/

如何实现的只读特性?

底层数据结构

字符串在运行时表示为:

type StringHeader struct {Data uintptr // 指向底层字节数组的指针Len  int     // 字符串长度
}
  • Data指向只读内存区域
  • 无修改字符串内容的操作接口
编译器级别的保护

编译错误

s := "hello"
s[0] = 'H' // 编译错误: cannot assign to s[0]
运行时保护

运行时机制

  1. 只读内存段
  • 字符串字面量存储在二进制文件的.rodata(只读数据段)
  • 程序加载时,操作系统将其映射到只读内存页
  1. 写保护内存页
    现代操作系统对只读内存页设置写保护:
内存页权限:
.rodata 段: R-- (只读不可写)
.data 段: RW- (可读写)
.text 段: R-X (可读可执行)
  1. 硬件级保护
  • CPU 内存管理单元(MMU)拦截非法写操作
  • 触发操作系统级保护异常(SIGSEGV)

二、引用类型(Reference Types)

包含的类型

  • 切片(slice
  • 映射(map
  • 通道(channel
  • 函数(func
  • 指针(pointer
  • 接口(interface

核心特点:

  1. 存储的是引用(指针)

    m1 := map[string]int{"a": 1}
    m2 := m1  // 复制引用(共享底层数据)
    m2["a"] = 100
    fmt.Println(m1["a"]) // 100(值被修改)
    
  2. 零值为 nil

    var s []int        // nil slice
    var m map[string]int // nil map
    // 操作 nil 引用会导致运行时错误
    
  3. 不可直接比较

    s1 := []int{1,2}
    s2 := []int{1,2}
    // fmt.Println(s1 == s2) // 编译错误(slice 不可比较)
    // 只能与 nil 比较: fmt.Println(s1 == nil)
    
  4. 函数传递效率高

    func process(slice []int) {// 只传递 24 字节的切片头(ptr+len+cap)
    }
    data := make([]int, 1000000) // 底层数组很大
    process(data)               // 高效传递
    
  5. 共享底层数据风险

    original := []int{1,2,3,4}
    sub := original[:2] // 共享同一个底层数组
    sub[0] = 99
    fmt.Println(original[0]) // 99(意外修改!)
    

内存存储

类型底层结构描述符大小特点
slice{ptr *T, len int, cap int}24字节cap ≥ len,可动态增长
map指向 runtime.hmap 的指针8字节哈希桶+溢出链
chan指向 runtime.hchan 的指针8字节环形队列+同步原语
func函数入口地址指针8字节闭包捕获外部变量
pointer目标内存地址8字节可指向任意类型
interface{_type *rtype, data unsafe.Pointer}16字节动态分发基础

需要特别注意的场景

1. 切片扩容陷阱

s := make([]int, 2, 4) // [0,0] 容量4
s1 := s[:2]           // 共享底层数组s = append(s, 5)     // 容量够,未扩容
s1[0] = 1            // 修改共享数组
fmt.Println(s[0])    // 1(被修改)s = append(s, 6,7)   // 超过容量,新建数组
s1[0] = 2           // 不再影响 s
fmt.Println(s[0])    // 1(未改变)

2. Map 并发访问危险

m := make(map[int]int)
go func() {for { m[1]++ } // 并发写
}()
go func() {for { _ = m[1] } // 并发读
}()
// 可能触发 fatal error: concurrent map read and map write

解决方案

  • 使用 sync.Mutexsync.RWMutex
  • 使用 sync.Map(Go 1.9+)

3. 接口的特殊行为

var w io.Writer = os.Stdout
w.Write([]byte("hello")) // 正确var w2 io.Writer
// w2.Write(...)  // 运行时 panic: nil pointer

关键点

  • 接口变量存储 (type, value)
  • 值为 nil 但类型非空的接口不等于 nil
    var buf *bytes.Buffer
    var w io.Writer = buf
    fmt.Println(w == nil) // false!(类型为 *bytes.Buffer)
    

4. 指针接收者与方法

type Counter struct{ n int }func (c *Counter) Inc() { c.n++ } // 指针接收者c := Counter{}
c.Inc()    // 自动转换为 (&c).Inc()
fmt.Println(c.n) // 1

规则

  • 值类型可调用指针接收者方法(Go 自动取地址)
  • 指针类型可调用值接收者方法(Go 自动解引用)

性能优化建议

  1. 大结构体用指针传递

    type LargeStruct struct { data [1024]byte }// 避免复制开销
    func (s *LargeStruct) Process() {}
    
  2. 避免不必要的堆分配

    // 不佳:返回指针导致堆分配
    func newPoint() *Point { return &Point{x: 1} }// 推荐:返回值(可能栈分配)
    func newPoint() Point { return Point{x: 1} }
    
  3. 预分配切片/映射容量

    // 避免频繁扩容
    users := make([]User, 0, 1000)
    cache := make(map[string]int, 100)
    

特殊类型指南

类型值/引用比较复制行为注意要点
数组深拷贝传参效率低
切片引用复制引用小心共享数据和扩容
Map引用复制引用非并发安全,需加锁
通道引用✅*复制引用比较相同通道对象
接口引用复制描述符有运行时开销
函数引用复制函数指针可作一等公民使用
字符串复制描述符底层数据只读共享

(*) 通道可比较:相同通道实例比较为 true

总结关键点

  1. 修改行为:引用类型会修改所有引用同一数据的变量
  2. 零值处理:引用类型零值为 nil,需显式初始化
  3. 并发安全:基本值类型原子操作安全,引用类型需要同步
  4. 性能取舍
    • 小对象:优先用值类型(栈分配)
    • 大对象:用指针或引用类型(避免复制)
  5. 比较限制:切片、map、函数等不可比较
  6. 接口陷阱nil 接口 != nil 具体值

理解这些差异可以帮助你避免常见陷阱(如意外数据共享、nil指针panic)并编写更高效的Go代码。

三、各个类型的指针操作

1. 基础指针操作

var a int = 42
p := &a  // 获取地址// 解引用操作
*p = 100  // a 变为 100
fmt.Println(a == *p) // true

2. 结构体指针优化

type Point struct{ X, Y float64 }// 直接通过指针访问字段(编译器自动优化)
p := &Point{1, 2}
p.Y = 3 // 等价于 (*p).Y = 3

3. 切片指针操作

data := []int{1, 2, 3}
ptr := &data[0]   // 获取首元素地址
*ptr = 100        // data[0] = 100// 危险操作:访问越界元素
// badPtr := &data[5]  // 编译通过但运行时 panic

4. unsafe 高级指针操作

import "unsafe"type Secret struct {id   int32flag uint16
}s := Secret{1024, 0xABCD}
ptr := unsafe.Pointer(&s)// 访问结构体内部字段
idPtr := (*int32)(ptr)          // 获取 id 字段指针
flagPtr := (*uint16)(unsafe.Pointer(uintptr(ptr) + unsafe.Offsetof(s.flag)))fmt.Println(*idPtr)   // 1024
fmt.Printf("%X", *flagPtr) // ABCD

四、各类型特殊注意事项

1. 字符串:只读字节序列

s := "hello"
// s[0] = 'H' // 编译错误:不可修改// 安全转换:string ↔ []byte
bytes := []byte(s)  // 复制数据创建新切片
str := string(bytes) // 同样复制数据

2. 切片:三大核心陷阱

陷阱 1:共享底层数组

original := []int{1,2,3,4,5}
sub := original[1:3] // 共享底层数组sub[0] = 100 // 修改影响 original[1]
fmt.Println(original) // [1,100,3,4,5]

陷阱 2:append 自动扩容

s := make([]int, 2, 3) // len=2, cap=3
s1 := append(s, 1)    // 共用底层数组
s2 := append(s, 2)    // 仍然共用到 cap=3s2[0] = 100           // 意外修改 s 和 s1
fmt.Println(s[0])     // 100(预期为 0)

陷阱 3:空切片 vs nil 切片

var nilSlice []int      // nil,与 nil 相等
emptySlice := []int{}   // 非 nil,已分配描述符fmt.Println(nilSlice == nil)   // true
fmt.Println(emptySlice == nil)  // false

3. Map:特殊的引用类型

m := make(map[string]int)
m["a"] = 1// 错误:禁止取元素地址
// p := &m["a"]  // 编译错误:无法获取地址// 正确访问方式
val, exists := m["a"]

4. 接口:双重指针设计

var w io.Writer
w = os.Stdout     // 存储 {*os.File类型信息, *os.File值指针}// nil 接口 != nil 具体值
var buf *bytes.Buffer
w = buf            // w != nil(类型信息非空)
if w == nil {      // false /* ... */ 
}

五、高效内存操作指南

1. 内存复用技巧

// 重用切片内存(避免重复分配)
pool := make([]*Object, 0, 100)func getObject() *Object {if len(pool) > 0 {obj := pool[len(pool)-1]pool = pool[:len(pool)-1]return obj}return &Object{}
}

2. 零拷贝转换(unsafe 实现)

// string → []byte(零拷贝)
func stringToBytes(s string) []byte {return *(*[]byte)(unsafe.Pointer(&struct {s stringc int}{s, len(s)},))
}
// 注意:结果切片只读!

3. 避免意外内存泄漏

func process() {bigData := make([]byte, 10<<20) // 10MB// 切片截取导致大内存无法回收smallPart := bigData[:10]// 解决方案:复制需要的数据result := make([]byte, 10)copy(result, bigData[:10])
} // 整个 10MB 可被回收

六、指针操作安全规范

1. 禁止指针运算(除 unsafe)

   arr := [3]int{1,2,3}p := &arr[0]// p++ // 禁止:Go 不支持指针算术

2. 内存对齐检查

   type BadLayout struct {a bool    // 1字节b int64   // 8字节 (需要7字节填充)}             // 总大小16字节而非9字节

3. cgo 指针安全

   /*#include <stdlib.h>*/import "C"import "unsafe"func copyToC(data []byte) {cptr := C.malloc(C.size_t(len(data)))defer C.free(cptr)// 通过unsafe转换C.memcpy(cptr, unsafe.Pointer(&data[0]), C.size_t(len(data)))}

4. 引用类型禁止取元素地址

m := map[int]string{1: "one"}
// 以下操作非法!因为map元素可能被重新散列迁移
// p := &m[1]

5. 切片的安全操作

s := []int{1,2,3}
first := &s[0] // 允许取元素地址
*first = 100   // 合法操作(底层数组稳定)

七、性能优化对照表

操作推荐方式避免方式性能提升
大结构体传参func(p *Struct)func(s Struct)8x+
小结构体传参func(s Struct)func(p *Struct)15-20%
大切片传递func(s []T)func(arr [10000]T)10000x
临时对象创建sync.Pool重复 new3-5x
字符串拼接strings.Builder+ 操作符10x+
Map 初始化m := make(map[K]V, hint)无预设容量2-3x

存储,指针操作总结

  1. 存储本质

    • 值类型:直接存储数据
    • 引用类型:存储描述符(指针+元数据)
    • 特殊类型:字符串只读、接口双层指针
  2. 指针安全

    • 常规代码避免使用 unsafe
    • 禁止取 map 元素地址
    • 注意切片共享的陷阱
  3. 性能关键

    • 大对象用指针传递
    • 预分配切片/map容量
    • 避免不必要的数据复制
  4. 内存管理

    • 理解逃逸分析机制
    • 复用内存(sync.Pool)
    • 避免因切片截取导致内存泄漏

八、不同类型的重点

切片扩容

Go语言在runtime/slice.go中的实现(go版本1.24),切片扩容的规则可以总结如下:

  1. 核心函数growslice
func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
  • oldPtr: 原切片底层数组指针
  • newLen: 扩容后的新长度
  • oldCap: 原切片容量
  • num: 新增元素数量
  • et: 元素类型信息
  1. 切片(slice)扩容容量计算的函数
// nextslicecap computes the next appropriate slice length.
func nextslicecap(newLen, oldCap int) int {//首先检查新长度是否超过旧容量的2倍,如果是则直接返回新长度newcap := oldCapdoublecap := newcap + newcapif newLen > doublecap {return newLen}
//对于容量小于256的小切片,采用双倍扩容策略const threshold = 256if oldCap < threshold {return doublecap}/*对于大切片,采用平滑过渡策略:
初始增长因子约为1.25倍
通过位运算>>2实现快速除以4
循环直到找到足够大的容量
*/for {// Transition from growing 2x for small slices// to growing 1.25x for large slices. This formula// gives a smooth-ish transition between the two.newcap += (newcap + 3*threshold) >> 2// We need to check `newcap >= newLen` and whether `newcap` overflowed.// newLen is guaranteed to be larger than zero, hence// when newcap overflows then `uint(newcap) > uint(newLen)`.// This allows to check for both with the same comparison.if uint(newcap) >= uint(newLen) {break}}// Set newcap to the requested cap when// the newcap calculation overflowed.//如果计算过程中出现溢出(负数),则直接返回新长度if newcap <= 0 {return newLen}return newcap
}

扩容策略

  1. 首先检查新长度是否超过旧容量的2倍,如果是则直接返回新长度
  2. 对于容量小于256的小切片,采用双倍扩容策略
  3. 对于大切片,采用平滑过渡策略:
  • 初始增长因子约为1.25倍
  • 通过位运算>>2实现快速除以4
  • 循环直到找到足够大的容量
  1. 如果计算过程中出现溢出(负数),则直接返回新长度

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

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

相关文章

uniapp——轮播图、产品列表轮播、上一页、下一页、一屏三张图

案例展示 组件封装 <template><view><view class="showSwiperBox"><view class="topSwiper"><swiper class="swiper" :autoplay="autoplay" interval="5000" :previous-margin="margin&qu…

用Python实现安全封装EXE文件加密保护工具

一、概述 这个Python脚本实现了一个强大的EXE文件加密保护工具,它能够将任何Windows可执行文件封装到一个带密码保护的GUI程序中。核心功能包括: 使用AES-256加密算法保护原始EXE文件 创建美观的密码验证界面 支持自定义程序图标 自动处理PyInstaller打包过程 修复Tkinter在…

vue3监听属性watch和watchEffect的详解

文章目录 1. 前言2. 常规用法3. 监听对象和route变化4. 使用场景4.1 即时表单验证4.2 搜索联想功能4.3 数据变化联动处理 5. watchEffect详解5-1 基本概念5-2 核心用法基础示例&#xff1a;自动响应依赖变化处理异步副作用停止监听与清理副作用 5-3 高级场景应用监听多个响应式…

Spring IoC核心实现揭秘

Spring IoC(控制反转)的实现机制是Spring框架的核心,其本质是将对象的创建、依赖管理和生命周期控制权从应用程序代码转移到容器中。以下是其核心实现机制: 🔧 一、核心实现步骤 配置元数据加载 容器启动时读取XML/注解/Java配置类,解析为BeanDefinition对象(包含类名、…

Solidity内部合约创建全解析:解锁Web3开发新姿势

合约创建基础 new 关键字创建合约 在 Solidity 中&#xff0c;new关键字是创建合约实例的最基本方式&#xff0c;它就像是一个 “魔法钥匙”&#xff0c;能够在以太坊区块链上生成一个全新的合约实例。使用new关键字创建合约的过程非常直观&#xff0c;就像我们在其他编程语言…

OCR大模型,破解金融文档处理困境,从文字识别到文字理解

金融机构在日常运营中处理海量文档。这些文档类型多样&#xff0c;格式复杂&#xff0c;是业务运营的基础。如何高效、准确地处理这些文档&#xff0c;直接影响机构的运营效率与风险控制水平。新一代的OCR大模型技术为此提供了有效的解决方案。它提升了文档处理的自动化程度与数…

2025.6.21笔记(2)

1.编写一个程序&#xff0c;输入一个整数&#xff0c;判断它是奇数还是偶数 解题思路&#xff1a; 1.因为要判断输入的数是奇数还是偶数&#xff0c;所以要用到if判断 2.判读奇偶数&#xff1a;如果这个数%20&#xff0c;则它为偶数&#xff0c;如果这个数%2!0&#xff0c;则…

【Ambari3.0.0 部署】Step7—Mariadb初始化-适用于el8

如果有其他系统部署需求可以参考原文 https://doc.janettr.com/install/manual/ MariaDB 10 是 Ambari 及大数据平台的常见数据库方案。本文适配 Rocky Linux 8.10&#xff0c;涵盖 MariaDB 10.11 推荐安装、YUM 源配置、参数优化、初始化和安全设置&#xff0c;帮助你一步到位…

SpringBoot电脑商城项目--删除收获地址+热销排行

删除收获地址 1 删除收获地址-持久层 1.1 规划sql语句 在删除操作之前判断该数据是否存在&#xff0c;判断该条地址的归属是否是当前的用户执行删除收货地址的操作 delete from t_address where aid? 如果用户删除的时默认地址&#xff0c;将剩下地址的某一条作为默认收货地…

MIMIC-III 数据集文件简介

文件简介&#xff1a; 共26个文件 admissions.csv 患者入院信息&#xff08;入院时间、出院时间、入院类型、科室等&#xff09;。 callout.csv ICU 外科室请求 ICU 会诊的呼叫记录。 caregivers.csv 护理患者的医护人员信息&#xff08;身份、角色等&#xff09;。…

UL/CE双认证!光宝MOC3052-A双向可控硅输出光耦 智能家居/工业控制必备!

光宝MOC3052-A双向可控硅输出光耦详解 1. 产品定位 MOC3052-A 是光宝科技&#xff08;Lite-On&#xff09;推出的 双向可控硅驱动光耦&#xff0c;属于光电隔离型半导体器件&#xff0c;主要用于交流负载的隔离控制&#xff0c;实现低压控制电路&#xff08;如MCU&#xff09;…

让没有小窗播放的视频网站的视频小窗播放

让没有小窗播放的视频网站的视频小窗播放 // 视频小窗播放控制台脚本 // 将此代码复制到浏览器控制台运行 // 运行后&#xff0c;页面中的视频将添加小窗播放功能(function() {// 获取页面中的所有video元素const videos document.querySelectorAll(video);if (videos.length…

Linux内核在启动过程中挂载根文件系统rootfs的过程

一、挂载根文件系统rootfs的过程&#xff1a; 1. ‌初始虚拟根文件系统的挂载‌ 内核启动时首先会创建并挂载一个‌临时虚拟根文件系统&#xff08;如initramfs或rootfs&#xff09;‌‌15。该阶段主要作用&#xff1a; 提供基础的设备节点和目录结构&#xff0c;确保内核能访…

【LeetCode】力扣题——轮转数组、消失的数字、数组串联

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训 &#x1f349;学习方向&#xff1a;C/C方向 ⭐️人生格言&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;…

Java Stream详解

Java Stream详解 Stream 是 Java 8 引入的流式数据处理工具&#xff0c;可以像流水线一样对集合数据进行高效操作&#xff08;过滤、转换、统计等&#xff09;。核心特点&#xff1a; 链式操作&#xff1a;支持多个操作串联不修改原始数据&#xff1a;生成新结果支持并行处理…

Java回归循环理解

一、Java循环的四种 1. 传统for循环 - 精确控制的首选 // 遍历数组 int[] numbers {1, 2, 3, 4, 5}; for (int i 0; i < numbers.length; i) {System.out.println(numbers[i]); }// 嵌套示例&#xff1a;矩阵遍历 int[][] matrix {{1, 2}, {3, 4}}; for (int row 0; r…

飞腾D2000金融工控主板,点亮经济高质量发展

近年来&#xff0c;国家不断推出金融行业的政策和法规&#xff0c;推动金融业高质量发展。在国家大力推进金融行业改革和创新的大环境下&#xff0c;金融工控主板市场也迎来了新的发展机遇。随着国产CPU技术的不断突破&#xff0c;以及我国对金融安全重视程度的提高&#xff0c…

SimpleITK——创建nrrd体素模型

在介绍如何生成nrrd前&#xff0c;了解一下为什么医学影像上一般使用nrrd的体素模型&#xff1f; 为什么医学影像上一般使用nrrd的体素模型&#xff1f; 在医学影像领域&#xff0c;‌NRRD&#xff08;Nearly Raw Raster Data&#xff09;格式‌被广泛用于存储体素模型&#x…

Docker容器部署KES

一、安装部署 1&#xff0c;导入镜像 #导入镜像&#xff08;root用户&#xff09; [rootnode docker ]# mv kdb_x86_64_V008R006C009B0014.tar kingbase.tar [rootnode docker]# docker load -i kingbase.tar#查看镜像&#xff08;root用户&#xff09; [rootnode docker]# d…

C++基础练习 sort函数,用于排序函数

题目&#xff1a; https://acm.hdu.edu.cn/showproblem.php?pid2039 解答&#xff1a; #include <iostream> #include <cmath> #include <algorithm> using namespace std;double a[3]; int main(){int n;cin>>n;while(n--){cin>>a[0]>>…