gin框架教程笔记

news2024/9/25 11:11:43

参考

官方中文文档:https://gin-gonic.com/zh-cn/docs/introduction/ 但是示例截图少
https://www.kancloud.cn/shuangdeyu/gin_book/949411
https://www.topgoer.com/gin%E6%A1%86%E6%9E%B6/ 这个网站不光有gin框架 适合阅读

吉米老师的 :https://www.liwenzhou.com/posts/Go/Gin_framework/
他的其他链接:https://www.liwenzhou.com/posts/Go/golang-menu/
docker部署go项目:https://www.liwenzhou.com/posts/Go/how_to_deploy_go_app_using_docker/

官方网站:https://gin-gonic.github.io/gin/
Github地址:https://github.com/gin-gonic/gin

什么是框架

框架是指半成品的应用,一般需要填充少许代码或者无需填充代码就可以运行,只是这样的应用缺少业务逻辑。

我们使用框架开发,主要工作就是在框架上补充业务逻辑代码。所以,借助框架进行开发,不仅可以减少开发时间、提高效率,也有助于团队统一编码风格,形成 编程规范。

gin 框架是一个 Web 框架,它封装了 路由、Cookie、Session、参数处理、数据编解码以及中间件等功能,简单高效,降低了开发 Web 应用的难度。

gin 是一个使用 Go 语言编写的 Web 后端框架,具有简洁、轻量、支持高并发、封装优雅、API 友好、快速灵活、容错方便等特点。

gin 和 beego 是 Go 语言编写 Web 应用最常用的后端框架。

使用 Go 语言开发 Web 应用,对于框架的依赖要比其它编程语言要小。Go 语言内置的 net/http 包简单轻便,性能优良。而且,大多数的 Go 语言 Web 框架都是在其之上进行的封装。

安装与导入

$ go get -u github.com/gin-gonic/gin
import (
	"net/http" //通常还需要导入 net/http 包,因为代码中一般需要一些常量,比如返回码 http.StatusOK。
	"github.com/gin-gonic/gin"
)

在这里插入图片描述

学学这个排版。

Hello World

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
   // 1.创建路由
   engine := gin.Default()
   
   // 2.绑定路由规则,执行的函数,这里写成了匿名函数的形式 也可单独写一个函数
   // gin.Context,封装了request和response
   //指定对什么网址进行相应,响应什么内容
   engine.GET("/", func(c *gin.Context) {
      c.String(http.StatusOK, "Hello World!")
   })
   
   // 3.监听端口,默认在8080
   engine.Run()//相当于 engine.Run(":8080")
}

上面GET方法可拆为:

helloHandler := func(context *gin.Context) {
	 context.String(http.StatusOK, "Hello World!")
}
func main() {
	//···省略
	engine.GET("/",helloHandler)
}

//GET is a shortcut for router.Handle("GET", path, handle)
helloHandler := func(context *gin.Context) {
	fmt.Fprint(context.Writer, "Hello World!")
}
r.Handle("GET", "/hello", helloHandler)

打开浏览器,输入 http://localhost:8080,就可以看到浏览器输出:

Hello World!

如果我们不使用gin框架,原生的go也可以实现:
在这里插入图片描述

路由处理

什么是路由

在web开发中,“route”是指根据url分配到对应的处理程序。

路由(route)就是根据 HTTP 请求的 URL,设置由哪个函数来处理请求。路由是 Web 框架的核心功能。

路由通常这样实现:根据路由里的字符 “/”,把路由切分成多个字符串数组,然后构造成树状结构;寻址的时候,先把请求的 URL 按照 “/” 进行切分,然后遍历树进行寻址。

比如:定义了两个路由 /user/get,/user/delete,则会构造出拥有三个节点的路由树,根节点是 user,两个子节点分别是 get 和 delete。

gin 框架路由库

gin 框架中采用的路由库是基于 httprouter 开发的。
httprouter 项目地址:https://github.com/julienschmidt/httprouter。

gin 框架路由的范例

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()

    // 下面是两条路由
    engine.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "编程教程")
    })

    engine.GET("/hello", func(c *gin.Context) {
        c.String(http.StatusOK, "Hello World")
    })
    // 监听端口默认为8080
    engine.Run(":8080")
}

运行程序,然后打开浏览器,输入 http://localhost:8080/,可以看到浏览器输出:编程教程。然后输入 http://localhost:8080/hello,可以看到浏览器输出:Hello World。

r.GET("/a",func(c *gin.Context) {})
r.POST("/b",func(c *gin.Context) {})
//此外,还有一个可以匹配所有请求方法的Any方法如下
r.Any("/c",func(c *gin.Context) {})

RESTAPI

web 应用程序,一般分为前端和后端两个部分。前后端通信通常需要一种统一机制,以方便不同的前端设备与后端进行通信。这种需求导致了 API 构架的流行,甚至出现 “API First” 的设计思想。

RESTful API 是目前比较成熟的一套 web 应用程序的 API 设计理论,用于 web 前后端的数据交互。

RESTful API 路径

RESTful API 的路径又称 “终点”(endpoint),表示 API 的具体网址。

在 RESTful 架构中,每个网址代表一种资源(resource),比如:有一个 API 提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样:

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

RESTful API HTTP 动词

在 RESTful API 设计理论中,对于资源的操作,由 HTTP 动词表示。

常用的 HTTP 动词有下面五个(括号里是对应的数据库 SQL 命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

比如

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

下面是一些例子

gin 框架支持 RESTful 风格的 API。

RESTful 即 Representational State Transfer 的缩写。直接翻译的意思是 “表现层状态转化”,是一种互联网应用程序的API设计理念:URL 定位资源,用 HTTP 方法描述操作,例如:

  1. 获取文章 /blog/getXxx Get blog/Xxx
  2. 添加文章 /blog/addXxx POST blog/Xxx
  3. 修改文章 /blog/updateXxx PUT blog/Xxx
  4. 删除文章 /blog/delXxxx DELETE blog/Xxx

在这里插入图片描述

gin 框架路由的基本语法

Gin 的路由支持 HTTP 的 GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS 方法的请求,同时还有一个 Any 函数,可以同时支持以上的所有请求。

Gin 的路由通常的使用方法如下:

// 获取默认的 gin Engine,Engine 中包含了所有路由处理的接口
engine := gin.Default()

// Get 请求路由
engine.GET("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin get method")
})
// Post 请求路由
engine.POST("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin post method")
})
// Put 请求路由 
engine.PUT("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin put method")
})
// Delete 请求路由
engine.DELETE("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin delete method")
})
// Patch 请求路由
engine.PATCH("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin patch method")
})
// Head 请求路由
engine.HEAD("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin head method")
})
// Options 请求路由
engine.OPTIONS("/", func(context *gin.Context) {
    context.String(http.StatusOK, "hello gin options method")
})

gin路由分组

我们在使用 web 框架开发时,经常会根据业务逻辑给一个模块划分一组路由。

把一个模块相关的方法都写在一个路由下,主要好处是业务逻辑清晰,便于管理和查找相关的代码。

例如:goods 为商品模块,我们规划它的操作路由。

/goods/addGoods 添加商品
/goods/delGoods 删除商品

gin 框架支持路由分组(routes group),路由分组的关键词为 group。

engine.Group("/groupname")

写法1

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func loginEndpoint(c *gin.Context){
    fmt.Println("这是login方法")
}

func submitEndpoint(c *gin.Context){
    fmt.Println("这是submit方法")
}

func readEndpoint(c *gin.Context){
    fmt.Println("这是read方法")
}

func main() {
    engine := gin.Default()

    //v1组路由     
    // {} 是书写规范  这个语法是咋实现的?  是函数先返回一个结构体 再实例化的意思么?
    v1 := engine.Group("/v1")
    {
        v1.GET("/login", loginEndpoint)
        v1.GET("/submit", submitEndpoint)
        v1.GET("/read", readEndpoint)
    }

    //v2组路由
    v2: = engine.Group("/v2")
    {
        v2.GET("/login", loginEndpoint)
        v2.GET("/submit", submitEndpoint)
        v2.GET("/read", readEndpoint)
    }
    engine.Run()
}

打开浏览器,输入 http://localhost:8080,分别访问:

http://localhost:8080/v1/login
http://localhost:8080/v1/submit
http://localhost:8080/v1/read
http://localhost:8080/v2/login
http://localhost:8080/v2/submit
http://localhost:8080/v2/read

浏览器会输出对应的 API 内容。

写法2

也可以这样:

func main() {
	r := gin.Default()
	user := r.Group("/user")
	user.GET("/index", func(c *gin.Context) {})
	user.POST("/login", func(c *gin.Context) {})
	r.Run()
}

在这里插入图片描述
区别,就在于不用再单独写路由了

参数处理

web 程序中经常需要处理各种形式的参数,参数是处理 HTTP 请求中很重要的工作,它是前端向后端提交数据的基本形式。

gin 框架内置了处理 HTTP 各种参数的方法,包括 API 参数,URL 参数 以及 表单参数的处理。

query参数处理(URL 参数处理)(get)

例如​/name=admin&pwd=123456​,我们想得到name和pwd的值

URL 参数可以通过 DefaultQuery() 或 Query() 方法获取。
DefaultQuery() 若参数不存在,则返回默认值,Query()若不存在,返回空串。

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		name := c.DefaultQuery("name", "admin")
		pwd := c.Query("pwd")
		// fmt.Printf("name:%s ; pwd:%s",name,pwd)
		c.JSON(http.StatusOK, gin.H{
			"name": name,
			"pwd":  pwd,
		})
	})
	r.Run()
}

表单Form参数处理 (post)

表单传输为post请求,http常见的传输格式为四种:

application/json
application/x-www-form-urlencoded
application/xml
multipart/form-data

表单参数可以通过 PostForm() 方法获取,该方法默认解析的是 x-www-form-urlencoded 或 from-data 格式的参数。

package main

import (
    "fmt"
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    engine.POST("/form", func(c *gin.Context) {
        types := c.DefaultPostForm("type", "post")
        username := c.PostForm("username")
        password := c.PostForm("userpassword")
        c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
    })
    engine.Run()
}

从表单中获取了 types、username、password 三个参数。

API 参数处理

gin 框架中,可以通过 Context 的 Param 方法来获取 API 参数。

比如:提取 http://localhost:8080/user/zhangsan 的参数 zhangsan。

package main

import (
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    engine.GET("/user/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.String(http.StatusOK, "name=" + name)
    })

    // 监听8080端口
    engine.Run(":8080")
}

运行程序,浏览器中输入:http://localhost:8080/user/zhangsan,浏览器会输出:name=zhangsan。

/user/:name/*action 这种也是api参数 后面会再讲

上传文件

简单来说 就是

FormFile("文件名")
<input type="file" name="file" >

上传单个文件

gin 框架中,multipart/form-data 格式用于文件上。

文件上传与原生的 net/http 方法类似,不同在于 gin 把原生的 request 封装到 c.Request 中。

前端 html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:
          <input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
</body>
</html>

文件可以保存为 test.html。

后端 go 文件:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    //限制上传最大尺寸
    engine.MaxMultipartMemory = 8 << 20
    engine.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            c.String(500, "上传图片出错")
        }
        // c.JSON(200, gin.H{"message": file.Header.Context})
        c.SaveUploadedFile(file, file.Filename)
        c.String(http.StatusOK, file.Filename)
    })
    engine.Run()
}

运行程序后,浏览器访问 test.html文件,就可以在浏览器中上传文件。

OR

前端页面代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f1">
    <input type="submit" value="上传">
</form>
</body>
</html>

后端Gin框架部分代码

package main

import (
	"fmt"
	"log"
	"net/http"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// r.MaxMultipartMemory = 8 << 20  // 8 MiB
	r.POST("/upload", func(c *gin.Context) {
		// 单个文件
		file, err := c.FormFile("f1")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"message": err.Error(),
			})
			return
		}

		log.Println(file.Filename)
		dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
		// 上传文件到指定的目录
		c.SaveUploadedFile(file, dst)
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
		})
	})
	r.Run()
}

上传特定文件

有的用户上传文件需要限制上传文件的类型以及上传文件的大小,但是 gin 框架暂时没有这些函数。因此,我们基于原生的函数写了一个可以限制大小以及文件类型的上传函数。

package main

import (
    "fmt"
    "log"
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    engine.POST("/upload", func(c *gin.Context) {
        _, headers, err := c.Request.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
        }
        //headers.Size 获取文件大小
        if headers.Size > 1024*1024*2 {
            fmt.Println("文件太大了")
            return
        }
        //headers.Header.Get("Content-Type")获取上传文件的类型
        if headers.Header.Get("Content-Type") != "image/png" {
            fmt.Println("只允许上传png图片")
            return
        }
        c.SaveUploadedFile(headers, "./video/"+headers.Filename)
        c.String(http.StatusOK, headers.Filename)
    })
    engine.Run()
}

上传多个文件

前端 html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:
          <input type="file" name="files" multiple>
          <input type="submit" value="提交">
    </form>
</body>
</html>

文件可以保存为 test.html。

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
   "fmt"
)

func main() {
   engine := gin.Default()
   // 限制表单上传大小 8MB,默认为32MB
   engine.MaxMultipartMemory = 8 << 20
   engine.POST("/upload", func(c *gin.Context) {
      form, err := c.MultipartForm()
      if err != nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
      }
      // 获取所有图片
      files := form.File["files"]
      // 遍历所有图片
      for _, file := range files {
         // 逐个保存
         if err := c.SaveUploadedFile(file, file.Filename); err != nil {
            c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
            return
         }
      }
      c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
   })
 
   engine.Run()
}

运行程序后,浏览器访问 test.html文件,就可以在浏览器中上传文件。

OR

package main

import (
	"fmt"
	"log"
	"net/http"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// r.MaxMultipartMemory = 8 << 20  // 8 MiB
	r.POST("/upload", func(c *gin.Context) {
		// Multipart form
		form, _ := c.MultipartForm()
		files := form.File["file"]

		for index, file := range files {
			log.Println(file.Filename)
			dst := fmt.Sprintf("C:/tmp/%s_%d", file.Filename, index)
			// 上传文件到指定的目录
			c.SaveUploadedFile(file, dst)
		}
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("%d files uploaded!", len(files)),
		})
	})
	r.Run()
}

中间件

Gin框架允许开发者在处理请求的过程中,加入钩子函数,这个钩子函数就叫中间件。中间件适合处理一些公共的业务逻辑,比如登陆认证,权限校验,记录日志等。具体使用方法如下

package main

import (
	"fmt"
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
)

//定义一个中间键m1统计请求处理函数耗时
func m1(c *gin.Context) {
	fmt.Println("m1 in...")
	start := time.Now()
	// c.Next() //调用后续的处理函数
	c.Abort()//阻止调用后续的处理函数
	cost := time.Since(start)
	fmt.Printf("cost:%v\n", cost)
}

func index(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"msg": "ok",
	})
}

func main() {
	r := gin.Default()
	r.GET("/", m1, index)  //之前没有中间件的写法r.GET("/", index)
	r.Run()
}

还没找到分类

func main() {
	r := gin.Default()

	// gin.H 是map[string]interface{}的缩写
	r.GET("/someJSON", func(c *gin.Context) {
		// 方式一:自己拼接JSON
		c.JSON(http.StatusOK, gin.H{"message": "Hello world!"})
	})
	r.GET("/moreJSON", func(c *gin.Context) {
		// 方法二:使用结构体
		var msg struct {
			Name    string `json:"user"`
			Message string
			Age     int
		}
		msg.Name = "小王子"
		msg.Message = "Hello world!"
		msg.Age = 18
		c.JSON(http.StatusOK, msg)
	})
	r.Run(":8080")
}

其中 方法一 等价
在这里插入图片描述
注意,结构体方法,变量名要大写。所以用tag

template

在一些前后端不分离的Web架构中,我们通常需要在后端将一些数据渲染到HTML文档中,从而实现动态的网页(网页的布局和样式大致一样,但展示的内容并不一样)效果。

我们这里说的模板可以理解为事先定义好的HTML文档文件,模板渲染的作用机制可以简单理解为文本替换操作–使用相应的数据去替换HTML文档中事先准备好的标记。

可以看这个:https://www.liwenzhou.com/posts/Go/go_template/

插件推荐

在这里插入图片描述

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

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

相关文章

unity报错出现Asset database transaction committed twice!

错误描述&#xff1a; 运行时报错 Assertion failed on expression: ‘m_ErrorCode MDB_MAP_RESIZED || !HasAbortingErrors()’Asset database transaction committed twice!Assertion failed on expression: ‘errors MDB_SUCCESS || errors MDB_NOTFOUND’ 解决办法&…

如何看待Figure公司与Open AI合作的最新机器人成果Figure 01?

想象一下&#xff0c;如果有一天&#xff0c;你走进办公室&#xff0c;迎面而来的不是熟悉的同事&#xff0c;而是一位名叫Figure 01的机器人新朋友。它不仅可以帮你倒咖啡&#xff0c;还能跟你聊天&#xff0c;甚至在你加班时给予精神上的支持。听起来是不是像科幻小说的情节&…

webpack5零基础入门-7webpack修改输出文件目录

1.修改output中的path后打包 path: path.resolve(__dirname, dist/js),//所有文件的输出目录 可以看到dist目录下多了个js目录 但所有文件都在js目录中 我们想要的是根据不同的资源进行分类很显然这样不行 从这里可以看出path是所有文件的输出目录 2.修改output中的filename…

Airtest-Selenium升级兼容Selenium 4.0,给你全新体验!

一、前言 在上期更新推文中提到&#xff0c;我们Airtest-Selenium更新到了1.0.6版本&#xff0c;新增支持Selenium4.0的语法&#xff0c;那么我们来看一下Airtest-Selenium更新后有什么新的内容吧~ 二、selenium 4.0有什么新功能 selenium4.0最主要的还是定位元素方法的更新…

基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

tar -xzf prometheus-2.7.0-rc.1.linux-amd64.tar.gzcd prometheus-2.7.0-rc.1.linux-amd64/./prometheus --config.fileprometheus.yml --web.listen-address:5555 Prometheus 默认监听端口号为 9090&#xff0c;为了不与系统上的其它进程监听端口冲突&#xff0c;我们在启动…

数据仓库为什么要分层建设?每一层的作用是什么?

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。为了更好地管理和利用这些数据&#xff0c;许多企业都建立了数据仓库。然而&#xff0c;数据仓库并非简单的数据存储工具&#xff0c;而是一个复杂的数据处理和分析系统。其中&#xff0c;分层建设是数据仓库设计的重…

net/http 框架源码解读

一、Hello World 使用net/http编写一个简单的web服务器, 定义了一个UserHandler的处理函数&#xff0c;通过HandleFunc来将路由和handler进行绑定&#xff0c;最后通过ListenAndServe启动web服务&#xff0c;后面我将handler统称为视图函数 package mainimport "net/htt…

探索非监督学习:解决聚类问题

目录 1 非监督学习的概念1.1 非监督学习的定义1.2 非监督学习的重要性 2 聚类问题的定义和意义2.1 聚类问题的定义2.2 聚类问题的意义2.3 聚类问题在非监督学习中的地位 3 聚类算法介绍3.1 K均值聚类3.2 层次聚类3.3 密度聚类 4 聚类问题的评估4.1 内部评估指标4.2 外部评估指标…

提升数据分析效率,选择IBM SPSS Statistics专业统计分析软件

在当今信息爆炸的时代&#xff0c;数据已经成为决策的重要依据。对于研究人员、学者、企业管理者等群体来说&#xff0c;如何高效地进行数据分析并得出准确结论至关重要。而IBM SPSS Statistics作为一款专业统计分析软件&#xff0c;为用户提供了强大的工具和功能&#xff0c;助…

Unreal发布Android在刘海屏手机上不能全屏显示问题

Unreal 4.27发布Android在刘海屏手机上不能全屏显示问题 Android设置全屏刘海屏全屏设置4.27设置刘海屏在部分手机不能显示问题 Android设置全屏 AndroidManifest.xml文件配置 ...<activity android:name"com.epicgames.ue4.GameActivity" android:label"st…

Claude 3 Haiku,它不仅是Claude系列中最快的成员,还在速度的赛道上领先一大步。

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

vr虚拟现实游戏世界介绍|数字文化展览|VR元宇宙文旅

虚拟现实&#xff08;VR&#xff09;游戏世界是一种通过虚拟现实技术创建的沉浸式游戏体验&#xff0c;玩家可以穿上VR头显&#xff0c;仿佛置身于游戏中的虚拟世界中。这种技术让玩家能够全方位、身临其境地体验游戏&#xff0c;与游戏中的环境、角色和物体互动。 在虚拟现实游…

一文解决Word中公式插入问题(全免费/latex公式输入/texsWord)

分文不花&#xff0c;搞定你的word公式输入/texsWord完全使用指南 背景 碎碎念&#xff1a;折折腾腾至少装了几个小时&#xff0c;遇到了若干大坑。遇到的问题网上都搜索不到答案&#xff01;&#xff01;&#xff01;就让我来当指路的小火柴吧。 本篇适用于在word中输入la…

微前端框架 qiankun 配置使用【基于 vue/react脚手架创建项目 】

qiankun官方文档&#xff1a;qiankun - qiankun 一、创建主应用&#xff1a; 这里以 vue 为主应用&#xff0c;vue版本&#xff1a;2.x // 全局安装vue脚手架 npm install -g vue/clivue create main-app 省略 vue 创建项目过程&#xff0c;若不会可以自行百度查阅教程 …

3D全景:为各行业提供更真实的交互体验

近年来&#xff0c;随着科技的不断发展&#xff0c;3D全景技术逐渐融入到了我们的日常生活中来。3D全景技术的应用落地&#xff0c;为广大用户提供了全新的视觉体验&#xff0c;让人们能够更加真实、直观地感受各行业的场景。 3D全景的优势就在于真实感和互动性&#xff0c;可以…

代码训练LeetCode(11)删除有序数组中的重复项II

代码训练(11)LeetCode之删除有序数组中的重复项II Author: Once Day Date: 2024年3月14日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 80. 删除有序数组中的重复项 II - 力扣&#xff08;LeetCode&#xff…

AI 大模型赋能手机影像,小米14 Ultra 让真实有层次

2月22日&#xff0c;小米龙年第一场重磅发布会&#xff0c;正式发布专业影像旗舰小米14 Ultra。 此前小米发布的两代 Ultra&#xff0c;在不同维度&#xff0c;引领了移动影像行业的走向。最新的小米14 Ultra 在定义的时候&#xff0c;我们反复在思考&#xff1a;怎么才能把移动…

三维高斯是什么

最近3DGS的爆火&#xff0c;引发了一众对三维高斯表达场景的研究。这里的三维高斯是什么&#xff1f;本文用简答的描述和简单实验来呈现三维高斯的数学意义。本文没有公式推导&#xff0c;主打一个意会。 我们高中都学过高斯分布&#xff0c;即一个钟形曲线。它的特点是有一个…

OpenAI的GPT-4.5 Turbo:意外曝光且可能在六月份推出

网络媒体THE DECODER的联合创始人兼出版人Matthias认为&#xff0c;人工智能技术将彻底改变人类和计算机的互动方式。 最新消息显示&#xff0c;OpenAI的最新力作GPT-4.5 Turbo已经在网络上意外曝光。首批发现此信息的是Bing和DuckDuck Go等搜索引擎&#xff0c;它们在官方发布…

吴恩达deeplearning.ai:独热编码One-hot连续有价值的特征回归树

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 One-hot编码连续有价值的特征回归树 在之前的决策树例子中&#xff0c;每个分裂都只有两种选择&#xff0c;但是今天我们将提到一种新的分裂方式叫做One-hot&#xff0c;可以解决以…