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

长安链使用Golang编写智能合约教程(二)

长安链2.3.0+的go合约虚拟机和2.3.0以下的不兼容,编译的方式也有差异,所以在ide上做了区分。

教程三会写一些,其他比较常用SDK方法的解释和使用方法

教程一:(长安链2.1.+的版本的智能合约)

教程三:(常见GO SDK的解释与使用) 


编写前的注意事项:

1、运行一条带有Doker_GoVM的链

2、建议直接用官方的在线IDE去写合约,因为写完可以直接测,缺点只是调试不方便。

3、如果自己拉环境在本地写合约,编译时注意编译环境,官方有提醒你去Linux下去编译

4、如果你的链是2.3.+,使用编译器前,请先切换到2.3.+,以防不测


1、首先去新建一个合约工程

这里选择空白模板,其他模板好像是一些web3的规范模板

2、打开main.go文件(有一份示例合约)

/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.SPDX-License-Identifier: Apache-2.0
*/package mainimport ("encoding/json""fmt""log""strconv""chainmaker/pb/protogo""chainmaker/sandbox""chainmaker/sdk"
)type FactContract struct {
}// 存证对象
type Fact struct {FileHash string FileName string Time     int 
}// 新建存证对象
func NewFact(fileHash string, fileName string, time int) *Fact {fact := &Fact{FileHash: fileHash,FileName: fileName,Time:     time,}return fact
}func (f *FactContract) InitContract() protogo.Response {return sdk.Success([]byte("Init contract success"))
}func (f *FactContract) UpgradeContract() protogo.Response {return sdk.Success([]byte("Upgrade contract success"))
}func (f *FactContract) InvokeContract(method string) protogo.Response {switch method {case "save":return f.Save()case "findByFileHash":return f.FindByFileHash()default:return sdk.Error("invalid method")}
}func (f *FactContract) Save() protogo.Response {params := sdk.Instance.GetArgs()// 获取参数fileHash := string(params["file_hash"])fileName := string(params["file_name"])timeStr := string(params["time"])time, err := strconv.Atoi(timeStr)if err != nil {msg := "time is [" + timeStr + "] not int"sdk.Instance.Errorf(msg)return sdk.Error(msg)}// 构建结构体fact := NewFact(fileHash, fileName, time)// 序列化factBytes, err := json.Marshal(fact)if err != nil {return sdk.Error(fmt.Sprintf("marshal fact failed, err: %s", err))}// 发送事件sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})// 存储数据err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes)if err != nil {return sdk.Error("fail to save fact bytes")}// 记录日志sdk.Instance.Infof("[save] fileHash=" + fact.FileHash)sdk.Instance.Infof("[save] fileName=" + fact.FileName)// 返回结果return sdk.Success([]byte(fact.FileName + fact.FileHash))}func (f *FactContract) FindByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果result, err := sdk.Instance.GetStateByte("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to call get_state")}// 反序列化var fact Factif err = json.Unmarshal(result, &fact); err != nil {return sdk.Error(fmt.Sprintf("unmarshal fact failed, err: %s", err))}// 记录日志sdk.Instance.Infof("[find_by_file_hash] fileHash=" + fact.FileHash)sdk.Instance.Infof("[find_by_file_hash] fileName=" + fact.FileName)// 返回结果return sdk.Success(result)
}func main() {err := sandbox.Start(new(FactContract))if err != nil {log.Fatal(err)}
}

3、示例模板解析

21行:这里的FactContract是合约名称,对应的要和125行main函数err := sandbox.Start(new(FactContract))一致

type FactContract struct {
}

25行:Fact结构体就是要存在区块链中的结构体,根据你自己的需要去变更结构体的字段

type Fact struct {
    FileHash string 
    FileName string 
    Time     int 
}

32行:新建存证对象,根据前面25行Fact 结构体的变化而变化

func NewFact(fileHash string, fileName string, time int) *Fact {
    fact := &Fact{
        FileHash: fileHash,
        FileName: fileName,
        Time:     time,
    }
    return fact
}

41-47行:InitContract、UpgradeContract两个方法,不用动,这是实现合约必须要的两个方法,用于合约初始化和合约升级

func (f *FactContract) InitContract() protogo.Response {
    return sdk.Success([]byte("Init contract success"))
}

func (f *FactContract) UpgradeContract() protogo.Response {
    return sdk.Success([]byte("Upgrade contract success"))
}

49行:InvokeContract是调用合约的方法,根据你的合约种有多少方法,依葫芦画瓢在case ....return 继续补充就行

func (f *FactContract) InvokeContract(method string) protogo.Response {
    switch method {
    case "save":
        return f.Save()
    case "findByFileHash":
        return f.FindByFileHash()
    default:
        return sdk.Error("invalid method")
    }
}

 60行: Save(存证方法)

以下大部分依葫芦画瓢就好了,重点关注以下内容:

66-72行:做了time字段的字符校验,确保是数字

84行:发送事件函数EmitEvent,第一个参数是合约事件主题,第二个参数是合约事件参数、(注意合约事件的数据,参数数量不可大于16写了事件、订阅之后可以监听到事件状态

87行:存储数据函数sdk.Instance.PutStateByte,三个参数 key、field 、value   ,(原本我以为弄个key-value的存储参数就行了,为什么官方要弄个field,我也不理解,但是官方有解释,不过用长安链就遵从他的规则吧)  这里就是说key是一个命名空间,相当于一个域,真正的key是一个拼接串,value是存证的内容。

93、94行:记录日志,可记可不记,写了的话,节点的日志记录会存下来

97行:返回要遵从官方规范

func (f *FactContract) Save() protogo.Response {
    params := sdk.Instance.GetArgs()

    // 获取参数
    fileHash := string(params["file_hash"])
    fileName := string(params["file_name"])
    timeStr := string(params["time"])
    time, err := strconv.Atoi(timeStr)
    if err != nil {
        msg := "time is [" + timeStr + "] not int"
        sdk.Instance.Errorf(msg)
        return sdk.Error(msg)
    }

    // 构建结构体
    fact := NewFact(fileHash, fileName, time)

    // 序列化
    factBytes, err := json.Marshal(fact)
    if err != nil {
        return sdk.Error(fmt.Sprintf("marshal fact failed, err: %s", err))
    }
    // 发送事件
    sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})

    // 存储数据
    err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes)
    if err != nil {
        return sdk.Error("fail to save fact bytes")
    }

    // 记录日志
    sdk.Instance.Infof("[save] fileHash=" + fact.FileHash)
    sdk.Instance.Infof("[save] fileName=" + fact.FileName)

    // 返回结果
    return sdk.Success([]byte(fact.FileName + fact.FileHash))

}

 取证方法:

以下大部分依葫芦画瓢就好了,重点关注以下内容:

  • 134行:取证的方法:sdk.Instance.GetStateByte ,这里的“fact_bytes”就是这个合约的域,所以这里填写的要和你在存证中填写的域一致才行。
  • 其他按照规范以葫芦画瓢

func (f *FactContract) FindByFileHash() protogo.Response {
    // 获取参数
    fileHash := string(sdk.Instance.GetArgs()["file_hash"])

    // 查询结果
    result, err := sdk.Instance.GetStateByte("fact_bytes", fileHash)
    if err != nil {
        return sdk.Error("failed to call get_state")
    }

    // 反序列化
    var fact Fact
    if err = json.Unmarshal(result, &fact); err != nil {
        return sdk.Error(fmt.Sprintf("unmarshal fact failed, err: %s", err))
    }

    // 记录日志
    sdk.Instance.Infof("[find_by_file_hash] fileHash=" + fact.FileHash)
    sdk.Instance.Infof("[find_by_file_hash] fileName=" + fact.FileName)

    // 返回结果
    return sdk.Success(result)
}

125行:main函数,这个new合约对象的时候保证名称和最开始21行的结构体名称一样就行了,其他的不用变。

func main() {
    err := sandbox.Start(new(FactContract))
    if err != nil {
        log.Fatal(err)
    }
}



4、新增一个查询历史数据的方法

以上就是main.go模板内容的解析,但是一般情况下,我们还有查询历史数据的需求,模板没有提供,所以这里根据模板继续补充一个查询历史记录的方法:

func (f *FactContract) GetHistoryByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果iter, err := sdk.Instance.NewHistoryKvIterForKey("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to delere get_state")}defer iter.Close()var keyModifications []*sdk.KeyModification// 遍历结果for {if !iter.HasNext() {break}keyModification, err := iter.Next()if err != nil {sdk.Instance.Infof("Error iterating: %v", err)}if keyModification == nil {break}keyModifications = append(keyModifications, keyModification)}jsonBytes, err := json.Marshal(keyModifications)if err != nil {return sdk.Error(fmt.Sprintf("Error marshaling keyModifications: %v", err))}// 返回结果return sdk.Success(jsonBytes)
}

方法解析:

这里我只解释重点步骤

1、调用查询历史数据接口

iter, err := sdk.Instance.NewHistoryKvIterForKey("fact_bytes", fileHash)

返回值类型:

后面就是根据返回值的结构进行遍历,

var keyModifications []*sdk.KeyModification

把结果放在 keyModifications  然后进行序列化,返回

 5、新增一个删除方法

注意,这里虽然是一个删除方法,但是不是真的删除,只有有一个isDelete的字段,如果调用了这个方法,某个域对应的hash会被标记为删除。代码不在解释

func (f *FactContract) DeleteByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果err := sdk.Instance.DelState("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to delere get_state")}// 返回结果return sdk.Success(nil)
}

6、完整合约

/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.SPDX-License-Identifier: Apache-2.0
*/package mainimport ("chainmaker/pb/protogo""chainmaker/sandbox""chainmaker/sdk""encoding/json""fmt""log""strconv"
)type FactContract struct {
}// 存证对象
type Fact struct {FileHash stringFileName stringTime     int
}// 新建存证对象
func NewFact(fileHash string, fileName string, time int) *Fact {fact := &Fact{FileHash: fileHash,FileName: fileName,Time:     time,}return fact
}func (f *FactContract) InitContract() protogo.Response {return sdk.Success([]byte("Init contract success"))
}func (f *FactContract) UpgradeContract() protogo.Response {return sdk.Success([]byte("Upgrade contract success"))
}func (f *FactContract) InvokeContract(method string) protogo.Response {switch method {case "save":return f.Save()case "findByFileHash":return f.FindByFileHash()case "deltedByFileHash":return f.DeleteByFileHash()case "getHistoryByFileHash":return f.GetHistoryByFileHash()default:return sdk.Error("invalid method")}
}func (f *FactContract) Save() protogo.Response {params := sdk.Instance.GetArgs()// 获取参数fileHash := string(params["file_hash"])fileName := string(params["file_name"])timeStr := string(params["time"])time, err := strconv.Atoi(timeStr)if err != nil {msg := "time is [" + timeStr + "] not int"sdk.Instance.Errorf(msg)return sdk.Error(msg)}// 构建结构体fact := NewFact(fileHash, fileName, time)// 序列化factBytes, err := json.Marshal(fact)if err != nil {return sdk.Error(fmt.Sprintf("传过来的参数序列化失败, err: %s", err))}// 发送事件sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})// 存储数据err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes)if err != nil {return sdk.Error("fail to save fact bytes")}// 记录日志// sdk.Instance.Infof("[save] fileHash=" + fact.FileHash)// sdk.Instance.Infof("[save] fileName=" + fact.FileName)createUser, _ := sdk.Instance.GetSenderRole()sdk.Instance.Infof("[saveUser] create=" + createUser)// 返回结果return sdk.Success([]byte(fact.FileName + fact.FileHash))}func (f *FactContract) FindByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果result, err := sdk.Instance.GetStateByte("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to call get_state")}// 反序列化var fact Factif err = json.Unmarshal(result, &fact); err != nil {return sdk.Error(fmt.Sprintf("unmarshal fact failed, err: %s", err))}// 记录日志sdk.Instance.Infof("[find_by_file_hash] fileHash=" + fact.FileHash)sdk.Instance.Infof("[find_by_file_hash] fileName=" + fact.FileName)// 返回结果return sdk.Success(result)
}func (f *FactContract) DeleteByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果err := sdk.Instance.DelState("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to delere get_state")}// 返回结果return sdk.Success(nil)
}func (f *FactContract) GetHistoryByFileHash() protogo.Response {// 获取参数fileHash := string(sdk.Instance.GetArgs()["file_hash"])// 查询结果iter, err := sdk.Instance.NewHistoryKvIterForKey("fact_bytes", fileHash)if err != nil {return sdk.Error("failed to delere get_state")}defer iter.Close()var keyModifications []*sdk.KeyModification// 遍历结果for {if !iter.HasNext() {break}keyModification, err := iter.Next()if err != nil {sdk.Instance.Infof("Error iterating: %v", err)}if keyModification == nil {break}keyModifications = append(keyModifications, keyModification)sdk.Instance.Infof("Key: %s, Field: %s, Value: %s, TxId: %s, BlockHeight: %d, IsDelete: %t, Timestamp: %s, \n",keyModification.Key, keyModification.Field, keyModification.Value, keyModification.TxId, keyModification.BlockHeight, keyModification.IsDelete, keyModification.Timestamp)}jsonBytes, err := json.Marshal(keyModifications)if err != nil {return sdk.Error(fmt.Sprintf("Error marshaling keyModifications: %v", err))}// 返回结果return sdk.Success(jsonBytes)
}func main() {err := sandbox.Start(new(FactContract))if err != nil {log.Fatal(err)}
}

7、结果展示

1、部署demo2合约

2、发起上链,上链了3条数据,其中file_hash我都是输入的1

3、查询某一个结果

4、删除一个结果

这也是一个上链操作

5、查询历史结果

这里没有格式化,现在拿去专门json格式化一下

[{"Key": "fact_bytes","Field": "1","Value": "eyJGaWxlSGFzaCI6IjEiLCJGaWxlTmFtZSI6IjIiLCJUaW1lIjozfQ==","TxId": "254071cabbca415186ae64956644d2230be111ebb94144d79f168a2252995a88","BlockHeight": 14,"IsDelete": false,"Timestamp": "1716864398"},{"Key": "fact_bytes","Field": "1","Value": "eyJGaWxlSGFzaCI6IjEiLCJGaWxlTmFtZSI6IjIiLCJUaW1lIjozfQ==","TxId": "ce705bbbaedb4315858b4e68b6331f4a947c3eb5a262433dbe2823ad3c87ee06","BlockHeight": 15,"IsDelete": false,"Timestamp": "1716864410"},{"Key": "fact_bytes","Field": "1","Value": "eyJGaWxlSGFzaCI6IjEiLCJGaWxlTmFtZSI6IjIiLCJUaW1lIjozfQ==","TxId": "6e099f7ce81543bf8fd0bf565f741478de53b4bc72834112a8bc0bc5f06f9a47","BlockHeight": 16,"IsDelete": false,"Timestamp": "1716864421"},{"Key": "fact_bytes","Field": "1","Value": "","TxId": "5f76c217063e41ad8c0f2b4ab3fae2418d784c9f0ade416b94715e95214acfc5","BlockHeight": 17,"IsDelete": true,"Timestamp": "1716864504"}
]

value就是存证的字符串,但是这里是base64编码,转码结果如下

(注意:这里你会发现所有的value都是一样的,因为是我存证的数据都是输入的一样的)

转码结果如下:




8、个人理解

  • 官方文档有错:官方文档把key叫做命名空间取了一个固定值,field作为存证hash,这里应该是他们写反了,field 才有域、空间的意思。上面的解析,我还是按照官方错误的来说的。因为他最后存在level_db中的key是拼接的,所以写反写没事,都一样。你可以改成对的。
  • 之所以引入一个命名空间的概念,我猜测应该是为了在数据库中方便查看,因为同一份id可能会被存多次,加了一个空间会方便区分。不过官方也提供了没有命名空间的存储方法PutStateFromKey(key string, value string) error  就是教程一用的方法
  • 删除函数,并不是真的删除,会新上链一条数据,标明某个域、某个key被删除了,但是已经上链的数据不会变动。

相关文章:

长安链使用Golang编写智能合约教程(二)

长安链2.3.0的go合约虚拟机和2.3.0以下的不兼容,编译的方式也有差异,所以在ide上做了区分。 教程三会写一些,其他比较常用SDK方法的解释和使用方法 教程一:(长安链2.1.的版本的智能合约) 教程三&#xff…...

jpom linux发布前端 ruoyi

前置条件 辅助安装 安装jdk curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdkonly-moduledefault 一键安装maven 后端必备 curl -fsSL https://jpom.top/docs/install.sh | bash -s Server mvnonly-moduledefault 一键安装node 前端必备 curl -fsSL http…...

K8S认证|CKA题库+答案| 15. 备份还原Etcd

目录 15、 备份还原Etcd CKA v1.29.0模拟系统 下载试用 题目: 开始操作: 1)、切换集群 2)、登录master并提权 3)、备份Etcd现有数据 4)、验证备份数据快照 5)、查看节点和Pod状态 6&#xff0…...

软件架构设计属性之一:功能性属性浅析

文章目录 引言一、定义二、关键要素1. 需求满足2. 操作性3. 数据处理4. 业务流程支持5. 合规性 三、 设计原则1. 用户中心设计2. 模块化3. 抽象化4. 可扩展性5. 可维护性6. 设计原则的实施策略7. 设计原则的评估 四、实现策略1. 需求分析2. 功能分解3. 接口设计4. 技术选型5. 迭…...

学习Java的日子 Day48 函数,DOM

Day48 1.流程控制语句 if else for for-in(遍历数组时,跟Java是否一样) While do while break 语句用于跳出循环 continue 用于跳过循环中的一个迭代 2.函数 2.1 JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function funct…...

Scikit-Learn朴素贝叶斯

Scikit-Learn朴素贝叶斯 1、朴素贝叶斯1.1、贝叶斯分类1.2、贝叶斯定理1.3、贝叶斯定理的推导1.4、朴素贝叶斯及原理1.5、朴素贝叶斯的优缺点2、Scikit-Learn朴素贝叶斯2.1、Sklearn中的贝叶斯分类器2.2、Scikit-Learn朴素贝叶斯API2.3、Scikit-Learn朴素贝叶斯实践(新闻分类与…...

网页设计步骤总结

第一步&#xff1a;css重置 https://blog.csdn.net/BradenHan/article/details/132122504 第二步&#xff1a;媒体查询不同尺寸加载不同的css文件https://blog.csdn.net/Yi_Lesama/article/details/131184469 <!-- link元素中的CSS媒体查询 --> <link rel"styl…...

第十三期Big Demo Day亮点项目:CCarbon重塑碳交易生态,助力全球绿色发展

第十三期Big Demo Day活动即将于2024年5月28日在香港数码港的CyberArena隆重举行。我们荣幸地宣布&#xff0c;利用区块链技术优化全球碳交易CCarbon项目将亮相&#xff0c;参与精彩的项目路演。本次活动由ZeeprLabs、BiKing Exchange、Gather冠名赞助&#xff0c;Central Rese…...

python基础知识总结(第一节)

一、python简介&#xff1a; Python是一种解释型&#xff0c;面向对象的高级语言。 Pyhton的语法和动态类型&#xff0c;以及解释性语言的本质&#xff0c;使它一跃成为多数平台上写脚本和快速开发应用的编程语言。 python语言百度百科介绍 二、Python基础语法&#xff1a;…...

DOS学习-目录与文件应用操作经典案例-comp

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 案例 1: 基本比较 案例 2: 十进制显示差异 案例 3: 字符形式显…...

原神抽卡点名程序教程(直接下载用)

今天我要给大家分享一个在抖音上特别火的视频——原神抽卡点名程序教程。 废话不多说&#xff0c;直接上链接 &#xff1a;--点击下载原神抽卡程序 步骤1&#xff1a; 步骤2&am…...

gpt-4o继续迭代考场安排程序 一键生成考场清单

接上两篇gpt-4o考场安排-CSDN博客&#xff0c;考场分层次安排&#xff0c;最终exe版-CSDN博客 当然你也可以只看这一篇。 今天又添加了以下功能&#xff0c;程序见后。 1、自动分页&#xff0c;每个考场打印一页 2、添加了打印试场单页眉 3、添加了页脚 第X页&#xff0c;…...

php 设置时区

date_default_timezone_set() 设置所有日期/时间函数使用的默认时区 除了在脚本中使用此函数设置默认时区&#xff0c;还可以使用 INI 设置 date.timezone 设置默认时区。 参数 timezoneId 时区标识符&#xff0c;像 UTC、Africa/Lagos、Asia/Hong_Kong 或 Europe/Lisbon。…...

ArcGIS不同图斑设置不同的透明度

对于设置一个图层的整体的透明度&#xff0c;我们在 ArcGIS制作带蒙版的遥感影像地图http://mp.weixin.qq.com/s?__bizMzIzNjM2NTYxMg&mid2247509080&idx1&sn38dccf0a52bb3bb3758f57114ee38b72&chksme8da161bdfad9f0d363da90959a8524dcf2b60d0e8d999f8ebeef0…...

前端 CSS 经典:图片边框

前言&#xff1a;有这么一个业务&#xff0c;需要边框随着图片宽度的变化而变化&#xff0c;比如一些聊天的气泡框等。 实现原理&#xff1a;使用 border-image 属性 效果图&#xff1a; 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><he…...

异常有什么,异常类有什么

在Java中&#xff0c;异常&#xff08;Exception&#xff09;是一种在程序运行过程中出现的不正常情况。异常机制提供了一种从错误中恢复的途径。异常分为两大类&#xff1a;检查异常&#xff08;Checked Exception&#xff09;和运行时异常&#xff08;Runtime Exception&…...

如何解压忘记了密码的加密zip压缩包?这两个方法收藏好!

加密是一种保护信息不被未经授权访问的重要手段。ZIP压缩包作为一种常见的文件压缩格式&#xff0c;zip文件加密是很多人都回去做的一件事情&#xff0c;那么zip加密文件如何解密&#xff1f;有几种方法可以解密呢&#xff1f;今天介绍几种方法给大家。 一、尝试常用密码 我们…...

java中,怎样用最简单方法实现写word文档

在跨平台环境中实现写word时&#xff0c;如果用现成的库&#xff0c;就会涉及跨平台兼容性问题&#xff0c;比如在安卓与java中实现写word的功能。还有一个问题就是&#xff0c;完全用程序生成word文档&#xff0c;工作量较大。所以采用了模板替换的方法。 docx文档本质就是一…...

大语言模型的工程技巧(三)——分布式计算

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文将讨论如何利用多台机器进行神经网络的分布式训练。利用多台机器来加速大语言模型的训练&#xff0c;是其获得成功的重要原…...

AI开发初体验:昇腾加持,OrangePi AIpro 开发板

文章目录 一、前言二、板子介绍2.1 拆箱2.2 板子规格2.2.1 常规项目2.2.2 扩展项目2.2.3 操作系统 2.3 点板画面 三、AI程序初体验3.1 新奇的地方3.2 运行第一个AI程序3.2.1 硬件连接3.2.2 串口连接3.2.3 开启外部IP端口3.2.4 查询板子IP地址3.2.5 了解 juypter lab 启动脚本&a…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...