go 连接服务器 并存放图片_基于 Go 语言开发在线论坛(二):通过模型类与MySQL数据库交互...

在这篇教程中,我们将在 MySQL 中创建一个 chitchat 数据库作为论坛项目的数据库,然后在 Go 项目中编写模型类与之进行交互。你可以本地安装 MySQL 数据库,也可以基于 Docker 容器运行(后续会介绍容器化启动方法)。

1、项目初始化

开始之前,我们先来初始化项目目录,我们将项目名设置为 chitchat,所以在 ~/Development/go/src/github.com/xueyuanjun 目录下创建这个项目目录,然后初始化目录结构如下:

bfac28969d1c8655f5266d33fbc4b4cb.png

重点看下红框内,各个子目录/文件的作用介绍如下:

  • main.go:应用入口文件

  • config.json:全局配置文件

  • handlers:用于存放处理器代码(可类比为 MVC 模式中的控制器目录)

  • logs:用于存放日志文件

  • models:用于存放与数据库交互的模型类

  • public:用于存放前端资源文件,比如图片、CSS、JavaScript 等

  • routes:用于存放路由文件和路由器实现代码

  • views:用于存放视图模板文件

接下来,我们在 chitchat 目录下运行如下命令初始化 go.mod,因为我们后续通过 Go Module 来管理依赖:

go mod init github.com/xueyuanjun/chitchat

2、创建数据表

开始正式编码之前,现在 chitchat 数据库中创建数据表,对应的 SQL 语句如下:

create table users (  id         serial primary key,  uuid       varchar(64) not null unique,  name       varchar(255),  email      varchar(255) not null unique,  password   varchar(255) not null,  created_at timestamp not null);create table sessions (  id         serial primary key,  uuid       varchar(64) not null unique,  email      varchar(255),  user_id    integer references users(id),  created_at timestamp not null);create table threads (  id         serial primary key,  uuid       varchar(64) not null unique,  topic      text,  user_id    integer references users(id),  created_at timestamp not null);create table posts (  id         serial primary key,  uuid       varchar(64) not null unique,  body       text,  user_id    integer references users(id),  thread_id  integer references threads(id),  created_at timestamp not null);

在 MySQL 客户端连接到 chitchat 数据库,运行上述 SQL 语句创建所有数据表:

e308e6996e07a6471ed30d1cfd42d7d7.png

3、与数据库交互

1)数据库驱动

数据表创建完成后,接下来,如何在 Go 应用代码中与数据库交互呢?Go 语言开发组并没有为此提供官方的数据库驱动实现,只是提供了数据库交互接口,我们可以通过实现这些接口的第三方扩展包完成与 MySQL 数据库的交互,本项目选择的扩展包是 go-mysql-driver 。

我们可以在 Go 应用中编写模型类基于这个扩展包提供的方法与 MySQL 交互完成增删改查操作,开始之前,可以运行如下命令安装这个依赖:

go get github.com/go-sql-driver/mysql

2)数据库连接

然后在 chitchat/models 目录下创建 db.go,并编写数据库连接初始化方法以及生成 UUID、哈希加密方法:

package modelsimport (    "crypto/rand"    "crypto/sha1"    "database/sql"    "fmt"    _ "github.com/go-sql-driver/mysql"    "log")var Db *sql.DBfunc init() {    var err error    Db, err = sql.Open("mysql", "root:root@/chitchat?charset=utf8&parseTime=true")    if err != nil {        log.Fatal(err)    }    return}// create a random UUID with from RFC 4122// adapted from http://github.com/nu7hatch/gouuidfunc createUUID() (uuid string) {    u := new([16]byte)    _, err := rand.Read(u[:])    if err != nil {        log.Fatalln("Cannot generate UUID", err)    }    // 0x40 is reserved variant from RFC 4122    u[8] = (u[8] | 0x40) & 0x7F    // Set the four most significant bits (bits 12 through 15) of the    // time_hi_and_version field to the 4-bit version number.    u[6] = (u[6] & 0xF) | (0x4 << 4)    uuid = fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])    return}// hash plaintext with SHA-1func Encrypt(plaintext string) (cryptext string) {    cryptext = fmt.Sprintf("%x", sha1.Sum([]byte(plaintext)))    return}

其中,Db 变量代表数据库连接池,通过 init 方法在 Web 应用启动时自动初始化数据库连接,这样,我们就可以在应用中通过 Db 变量对数据库进行增删改查操作了,这也是该变量首字母大写的原因,方便在 models 包之外被引用,具体的操作实现我们放到独立的模型文件中处理。

注:这里通过 sql.Open 初始化数据库连接,我们写死了数据库连接配置,在实际生产环境,这块配置值应该从配置文件或系统环境变量获取。

3)用户相关模型类

有了代表数据库连接池的 Db 变量之后,就可以为每个数据表编写对应的模型类实现增删改查操作了,首先在 models 目录下创建 user.go 用于定义用户模型类 User 与 users 表进行交互,以及与 sessions 表进行关联:

package modelsimport "time"type User struct {    Id        int    Uuid      string    Name      string    Email     string    Password  string    CreatedAt time.Time}// Create a new session for an existing userfunc (user *User) CreateSession() (session Session, err error) {    statement := "insert into sessions (uuid, email, user_id, created_at) values (?, ?, ?, ?)"    stmtin, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmtin.Close()    uuid := createUUID()    stmtin.Exec(uuid, user.Email, user.Id, time.Now())    stmtout, err := Db.Prepare("select id, uuid, email, user_id, created_at from sessions where uuid = ?")    if err != nil {        return    }    defer stmtout.Close()    // use QueryRow to return a row and scan the returned id into the Session struct    err = stmtout.QueryRow(uuid).Scan(&session.Id, &session.Uuid, &session.Email, &session.UserId, &session.CreatedAt)    return}// Get the session for an existing userfunc (user *User) Session() (session Session, err error) {    session = Session{}    err = Db.QueryRow("SELECT id, uuid, email, user_id, created_at FROM sessions WHERE user_id = ?", user.Id).        Scan(&session.Id, &session.Uuid, &session.Email, &session.UserId, &session.CreatedAt)    return}// Create a new user, save user info into the databasefunc (user *User) Create() (err error) {    // Postgres does not automatically return the last insert id, because it would be wrong to assume    // you're always using a sequence.You need to use the RETURNING keyword in your insert to get this    // information from postgres.    statement := "insert into users (uuid, name, email, password, created_at) values (?, ?, ?, ?, ?)"    stmtin, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmtin.Close()    uuid := createUUID()    stmtin.Exec(uuid, user.Name, user.Email, Encrypt(user.Password), time.Now())    stmtout, err := Db.Prepare("select id, uuid, created_at from users where uuid = ?")    if err != nil {        return    }    defer stmtout.Close()    // use QueryRow to return a row and scan the returned id into the User struct    err = stmtout.QueryRow(uuid).Scan(&user.Id, &user.Uuid, &user.CreatedAt)    return}// Delete user from databasefunc (user *User) Delete() (err error) {    statement := "delete from users where id = ?"    stmt, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmt.Close()    _, err = stmt.Exec(user.Id)    return}// Update user information in the databasefunc (user *User) Update() (err error) {    statement := "update users set name = ?, email = ? where id = ?"    stmt, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmt.Close()    _, err = stmt.Exec(user.Name, user.Email, user.Id)    return}// Delete all users from databasefunc UserDeleteAll() (err error) {    statement := "delete from users"    _, err = Db.Exec(statement)    return}// Get all users in the database and returns itfunc Users() (users []User, err error) {    rows, err := Db.Query("SELECT id, uuid, name, email, password, created_at FROM users")    if err != nil {        return    }    for rows.Next() {        user := User{}        if err = rows.Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.Password, &user.CreatedAt); err != nil {            return        }        users = append(users, user)    }    rows.Close()    return}// Get a single user given the emailfunc UserByEmail(email string) (user User, err error) {    user = User{}    err = Db.QueryRow("SELECT id, uuid, name, email, password, created_at FROM users WHERE email = ?", email).        Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.Password, &user.CreatedAt)    return}// Get a single user given the UUIDfunc UserByUUID(uuid string) (user User, err error) {    user = User{}    err = Db.QueryRow("SELECT id, uuid, name, email, password, created_at FROM users WHERE uuid = ?", uuid).        Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.Password, &user.CreatedAt)    return}

创建 session.go 用于定义会话模型类 Session

package modelsimport "time"type Session struct {    Id        int    Uuid      string    Email     string    UserId    int    CreatedAt time.Time}// Check if session is valid in the databasefunc (session *Session) Check() (valid bool, err error) {    err = Db.QueryRow("SELECT id, uuid, email, user_id, created_at FROM sessions WHERE uuid = ?", session.Uuid).        Scan(&session.Id, &session.Uuid, &session.Email, &session.UserId, &session.CreatedAt)    if err != nil {        valid = false        return    }    if session.Id != 0 {        valid = true    }    return}// Delete session from databasefunc (session *Session) DeleteByUUID() (err error) {    statement := "delete from sessions where uuid = ?"    stmt, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmt.Close()    _, err = stmt.Exec(session.Uuid)    return}// Get the user from the sessionfunc (session *Session) User() (user User, err error) {    user = User{}    err = Db.QueryRow("SELECT id, uuid, name, email, created_at FROM users WHERE id = ?", session.UserId).        Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.CreatedAt)    return}// Delete all sessions from databasefunc SessionDeleteAll() (err error) {    statement := "delete from sessions"    _, err = Db.Exec(statement)    return}

这里面定义了基于 Db 数据库连接实例实现用户模型和会话模型相关的增删改查操作,具体的语法可以参考 go-mysql-driver 的 官方文档,这里不详细展开,具体细节,我们留到后面专门介绍数据库模块时再详细说明。

4)主题相关模型类

编写好用户相关模型类后,接下来在同级目录下创建 thread.go,定义群组模型类 Thread 与 threads 表进行交互:

package modelsimport "time"type Thread struct {    Id        int    Uuid      string    Topic     string    UserId    int    CreatedAt time.Time}// format the CreatedAt date to display nicely on the screenfunc (thread *Thread) CreatedAtDate() string {    return thread.CreatedAt.Format("Jan 2, 2006 at 3:04pm")}// get the number of posts in a threadfunc (thread *Thread) NumReplies() (count int) {    rows, err := Db.Query("SELECT count(*) FROM posts where thread_id = ?", thread.Id)    if err != nil {        return    }    for rows.Next() {        if err = rows.Scan(&count); err != nil {            return        }    }    rows.Close()    return}// get posts to a threadfunc (thread *Thread) Posts() (posts []Post, err error) {    rows, err := Db.Query("SELECT id, uuid, body, user_id, thread_id, created_at FROM posts where thread_id = ?", thread.Id)    if err != nil {        return    }    for rows.Next() {        post := Post{}        if err = rows.Scan(&post.Id, &post.Uuid, &post.Body, &post.UserId, &post.ThreadId, &post.CreatedAt); err != nil {            return        }        posts = append(posts, post)    }    rows.Close()    return}// Get all threads in the database and returns itfunc Threads() (threads []Thread, err error) {    rows, err := Db.Query("SELECT id, uuid, topic, user_id, created_at FROM threads ORDER BY created_at DESC")    if err != nil {        return    }    for rows.Next() {        conv := Thread{}        if err = rows.Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt); err != nil {            return        }        threads = append(threads, conv)    }    rows.Close()    return}// Get a thread by the UUIDfunc ThreadByUUID(uuid string) (conv Thread, err error) {    conv = Thread{}    err = Db.QueryRow("SELECT id, uuid, topic, user_id, created_at FROM threads WHERE uuid = ?", uuid).        Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt)    return}// Get the user who started this threadfunc (thread *Thread) User() (user User) {    user = User{}    Db.QueryRow("SELECT id, uuid, name, email, created_at FROM users WHERE id = ?", thread.UserId).        Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.CreatedAt)    return}

以及 post.go 编写主题模型类与 posts 表进行交互:

package modelsimport "time"type Post struct {    Id        int    Uuid      string    Body      string    UserId    int    ThreadId  int    CreatedAt time.Time}func (post *Post) CreatedAtDate() string {    return post.CreatedAt.Format("Jan 2, 2006 at 3:04pm")}// Get the user who wrote the postfunc (post *Post) User() (user User) {    user = User{}    Db.QueryRow("SELECT id, uuid, name, email, created_at FROM users WHERE id = ?", post.UserId).        Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.CreatedAt)    return}

此外,我们到 user.go 中为 User 模型新增如下两个方法与 ThreadPost 模型进行关联,用于创建新的群组和主题:

// Create a new threadfunc (user *User) CreateThread(topic string) (conv Thread, err error) {    statement := "insert into threads (uuid, topic, user_id, created_at) values (?, ?, ?, ?)"    stmtin, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmtin.Close()    uuid := createUUID()    stmtin.Exec(uuid, topic, user.Id, time.Now())    stmtout, err := Db.Prepare("select id, uuid, topic, user_id, created_at from threads where uuid = ?")    if err != nil {        return    }    defer stmtout.Close()    // use QueryRow to return a row and scan the returned id into the Session struct    err = stmtout.QueryRow(uuid).Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt)    return}// Create a new post to a threadfunc (user *User) CreatePost(conv Thread, body string) (post Post, err error) {    statement := "insert into posts (uuid, body, user_id, thread_id, created_at) values (?, ?, ?, ?, ?)"    stmtin, err := Db.Prepare(statement)    if err != nil {        return    }    defer stmtin.Close()    uuid := createUUID()    stmtin.Exec(uuid, body, user.Id, conv.Id, time.Now())    stmtout, err := Db.Prepare("select id, uuid, body, user_id, thread_id, created_at from posts where uuid = ?")    if err != nil {        return    }    defer stmtout.Close()    // use QueryRow to return a row and scan the returned id into the Session struct    err = stmtout.QueryRow(uuid).Scan(&post.Id, &post.Uuid, &post.Body, &post.UserId, &post.ThreadId, &post.CreatedAt)    return}

4、小结

在上述编写的模型类中,模型类与数据表是如何映射的呢?这个由 go-mysql-driver 底层实现,每次从数据库查询到结果之后,可以通过 Scan 方法将数据表字段值映射到对应的结构体模型类,而将模型类保存到数据库时,又可以基于字段映射关系将结构体属性值转化为对应的数据表字段值。对应的底层交互逻辑如下所示:

62bda0982bc36306ed2dbbcc06fea681.png

再次重申,本项目旨在帮助大家快速熟悉 Go Web 项目的完整开发流程和代码组织架构,具体的技术实现细节留到后面单独的数据库模块详细介绍,不过,如果你之前有过其他语言的 Web 开发经验,比如 PHP、Python、Java,基本上看一眼这些代码就能知道个大概了,因为他们的实现思路都是相通的,无非是语言的语法不同而已,所以这也是学院君反复强调新人应该花个三五年时间先精通一门语言,再学习其他语言的原因。

底层数据库交互逻辑定义好了之后,接下来,我们就可以编写上层实现代码了,下一篇学院君将给大家演示在线论坛项目上层路由和处理器方法的实现。

推荐阅读

  • 基于 Go 语言编写在线论坛(一):整体设计与数据模型


喜欢本文的朋友,欢迎关注“Go语言中文网”:

16ed99501a22533bf138fa36118c3238.png

Go语言中文网启用微信学习交流群,欢迎加微信:274768166,投稿亦欢迎

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

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

相关文章

dax 筛选 包含某个字_DAX分享9:DAX中用变量来计算动态filter context中数值

文章写起来真的也挺麻烦的。坚持坚持&#xff01;加油加油&#xff01;本次分享的需求描述如下&#xff1a;在Power BI中创建一个页面&#xff0c;页面显示一个Table和两个Slicer。其中Slicer的内容也列在Table里。Table里需要一个计算值&#xff0c;这个计算值要求对Table中的…

c++怎么实现数字数组的删除数字_C/C++数据结构:栈结构解析,最简单解析,让你一遍就会...

上一章节针对于C语言最基本的数据结构链式结构体做了解析&#xff0c;不清楚的可以回顾一下。本章节主要针对于C语言的基础数据结构栈做以解析。数据结构之栈栈(stack)又名堆栈&#xff0c;它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶…

【总结记录】面向对象设计OOP三大特性(封装、继承、多态)、七大基本原则的理解(结合代码、现实实例理解)

文章目录一. 三大特征的理解&#xff08;1&#xff09;封装&#xff08;2&#xff09;继承&#xff08;3&#xff09;多态&#xff08;4&#xff09;面向对象、面向过程的对比二. 七大基本原则的理解&#xff08;1&#xff09;单一职责原则&#xff08;2&#xff09;开放封闭原…

arcmap shp导出cad无反应_如何使用ArcMap将Excel数据转换为shp数据

1. 概述对ArcMap而言&#xff0c;除了shapefile等数据源&#xff0c;还可以将包含地理位置的表格数据以 XY 坐标的形式添加到地图中&#xff0c;比如Excel格式的数据&#xff0c;如果包含有坐标数据在里面&#xff0c;就可以通过导入XY数据的方式将Excel数据导入&#xff0c;最…

【总结记录】《MySQL必知必会》读后笔记,结合 leetcode 例题理解

文章目录一. 《MySQL知会》读后笔记1. 零散的前文知识2. 连接数据库3. 检索数据&#xff08;重点开始了&#xff09;4. 排序、过滤数据5. 通配符、正则表达式6. 汇总数据7. 分组数据&#xff08;1&#xff09;GROUP BY&#xff08;数据分组&#xff09;&#xff08;2&#xff0…

如何使用CNN进行物体识别和分类_RCNN物体识别

R-CNN&#xff0c;图片识别目标检测(Object Detection)是图像分类的延伸&#xff0c;除了分类任务&#xff0c;还要给定多个检测目标的坐标位置。R-CNN是最早基于CNN的目标检测方法&#xff0c;然后基于这条路线依次演进出了SPPnet,Fast R-CNN和Faster R-CNN&#xff0c;然后到…

nfs服务器_Kubernetes集群下部署NFS持久存储

NFS是网络文件系统Network File System的缩写&#xff0c;NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地的文件系统中&#xff0c;而在本地的系统中来看&#xff0c;那个远程主机的目录就好像是自己的一个磁盘分区一样。kubernetes使用NFS共享存储有两种方式&…

c语言 指针_C 语言指针详解

(给CPP开发者加星标&#xff0c;提升C/C技能)作者&#xff1a;C语言与CPP编程 / 自成一派123(本文来自作者投稿)1为什么使用指针假如我们定义了 char a’A’ &#xff0c;当需要使用 ‘A’ 时&#xff0c;除了直接调用变量 a &#xff0c;还可以定义 char *p&a &#xff0c…

idea修改代码后不重启项目_使用DevTool实现SpringBoot项目热部署

前言最近在开发的时候&#xff0c;每次改动代码都需要启动项目&#xff0c;因为有的时候改动的服务比较多&#xff0c;所以重启的次数也就比较多了&#xff0c;想着每次重启等待也挺麻烦的&#xff0c;就打算使用DevTools工具实现项目的热部署热部署是什么大家都知道在项目开发…

c++ 单例模式_Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

redis作为一种高效的缓存框架&#xff0c;使用是非常广泛的&#xff0c;在数据存储上&#xff0c;在运行时其将数据存储在内存中&#xff0c;以实现数据的高效读写&#xff0c;并且根据定制的持久化规则不同&#xff0c;其会不定期的将数据持久化到硬盘中。另外相较于其他的NoS…

jenkins 插件目录_10 个 Jenkins 实战经验,助你轻松上手持续集成

众所周知&#xff0c;持续构建与发布是我们日常工作中要面对的的一个重要环节&#xff0c;目前很多公司都采用 Jenkins 来搭建符合需求的 CI/CD 流程&#xff0c;作为一个持续集成的开源工具&#xff0c;它以安装启动方便&#xff0c;配置简单&#xff0c;上手容易的特点&#…

jdbc 批量insert_JDBC相关知识解答

1. JDBC_PreparedStatement插入大量数据_批处理插入_效率比较(1) jdbc新增大量数据时, 如何处理能提高效率?答&#xff1a;使用批处理提高效率(2) 什么是批处理? JDBC如何进行批处理?答&#xff1a;批处理&#xff1a;在与数据库的一次连接中&#xff0c;批量的执行条 SQL 语…

python 实现显著性检测_强!汽车车道视频检测:python+OpenCV为主实现

1 说明&#xff1a;1.1 完整版&#xff1a;汽车车道动态视频检测讲解和注释版代码&#xff0c;小白秒懂。1.2 pythonOpenCVmoviepynumpy为主的技术要点。1.3 代码来源&#xff1a;https://github.com/linghugoogle/CarND-Advanced-Lane-Lines #虽然感觉也是fork别人的&#xff…

如何学习c语言 零基础20天学会C语言

C语言开发 学习C语言不是一朝一夕的事情&#xff0c;但也不需要花费十年时间才能精通。如何以最小的代价学习并精通C语言是本文的主题。请注意&#xff0c;即使是“最小的代价”&#xff0c;也绝不是什么捷径&#xff0c;而是以最短的时间取得最多的收获&#xff0c;同时也意味…

学习C/C++的简单方法

如何学习C呢。C和C是很多专业的必修课&#xff0c;尤其对计算机专业来说&#xff0c;更是重中之重。C语言是早期发展的高级语言&#xff0c;具备执行速度快&#xff0c;语法优美等特点。是底层高效率系统的首选开发语言。今天就和大家分享一下怎么学好C/C语言吧 _ 怎么学好C、…

python数据预处理代码_Python中数据预处理(代码)

本篇文章给大家带来的内容是关于Python中数据预处理&#xff08;代码&#xff09;&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。1、导入标准库import numpy as np import matplotlib.pyplot as plt import pandas as pd 2、…

零基础想学好C语言编程,首先要掌握的是正确的学习思路!

如果新手要学习编程&#xff0c;一些前辈都会建议从Python、PHP、Java开始学。 不过&#xff0c;有些程序员是直接从C语言强势入门编程的。 那么&#xff0c;如何学习C语言呢?下面提供4种入门C语言的方法&#xff1a; 0、刷题 绝大多数的程序员学编程的时候&#xff0c;还…

C/C++初学者快速提升?

如今&#xff0c;软件开发行业继续向前大步迈进。信息技术越来越吃香&#xff0c;越来越多人学习学习c语言&#xff0c;那么如何系统有效的学习C语言?下面分享给大家的有效学习语言的方法&#xff0c;希望可以帮到你! 一、了解大纲&#xff0c;通览教材 想学好C语言最重要的一…

pytorch 矩阵相乘_深度学习 — — PyTorch入门(三)

点击关注我哦autograd和动态计算图可以说是pytorch中非常核心的部分&#xff0c;我们在之前的文章中提到&#xff1a;autograd其实就是反向求偏导的过程&#xff0c;而在求偏导的过程中&#xff0c;链式求导法则和雅克比矩阵是其实现的数学基础&#xff1b;Tensor构成的动态计算…

codeblocks如何让输出结果 空格_简单讲讲如何实现两个正整数相加,然后输出这个结果...

首先吧&#xff0c;两个整数123 456&#xff0c;相加得到579&#xff0c;我们就得输出579&#xff0c;这个很容易操作&#xff0c;但是如果是&#xff1a;1212161596156198115645646886148461554 2671232162176217624372497590415915915029125 呢&#xff1f;long ? long lo…