Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang之Struct什么是结构体struct?

golang之Struct什么是结构体struct?

作者头像
若与
发布于 2018-04-25 06:40:01
发布于 2018-04-25 06:40:01
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

最近在复习golang,学习的东西,如果不使用,很快就会忘记。所以,准备复习完golang,做一个练手的小项目,加深对golang的学习。今天开始公司,进入封闭式开发,所以每天晚上回来,学习golang时间比较少了。所以,争取一天一章的学习。

学习资源: https://github.com/Unknwon, 无闻,golang的大牛,他的文档网站很不错。教学也很好。golang的在线测试 https://play.golang.org,直接在浏览器中测试。

struct的主要内容:

结构体的定义和使用 使用字面量初始化 匿名结构和字段 结构体之间的比较和赋值 嵌入结构 提升字段 字段属性的访问使用 引用传递和值传递

什么是结构体struct?

结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。就是面向对象编程语言中的类class

例如,一个职员有 firstNamelastNameage 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。

结构体的声明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Employee struct {
    firstName string
    lastName  string
    age       int
}

在上面的代码片段里,声明了一个结构体类型 Employee,它有 firstNamelastNameage 三个字段。通过把相同类型的字段声明在同一行,结构体可以变得更加紧凑。在上面的结构体中,firstNamelastName 属于相同的 string 类型,于是这个结构体可以重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Employee struct {
    firstName, lastName string
    age, salary         int
}

上面的结构体 Employee 称为 命名的结构体(Named Structure)。我们创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。

声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var employee struct {
    firstName, lastName string
    age int
}

上述代码片段创建一个匿名结构体 employee。匿名结构体是使用字面量直接初始化的。

创建命名的结构体

通过下面代码,我们定义了一个命名的结构体 Employee

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {

    //creating structure using field names
    emp1 := Employee{
        firstName: "youdi",
        age:       25,
        salary:    500,
        lastName:  "liang",
    }

    //creating structure without using field names
    emp2 := Employee{"hui", "liang", 26, 800}

    fmt.Println("Employee 1", emp1)
    fmt.Println("Employee 2", emp2)
}

在上述程序的第 7 行,我们创建了一个命名的结构体 Employee。而在第 15 行,通过指定每个字段名的值,我们定义了结构体变量 emp1。字段名的顺序不一定要与声明结构体类型时的顺序相同。在这里,我们改变了 lastName 的位置,将其移到了末尾。这样做也不会有任何的问题。

在上面程序中,定义 emp2 时我们省略了字段名。在这种情况下,就需要保证字段名的顺序与声明结构体时的顺序相同。

该程序将输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 1 {youdi liang 25 500}
Employee 2 {hui liang 26 800}

创建匿名结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
)

func main() {
    emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

    fmt.Println("Employee 3", emp3)
}

在上述程序的第 3 行,我们定义了一个匿名结构体变量 emp3。上面我们已经提到,之所以称这种结构体是匿名的,是因为它只是创建一个新的结构体变量 em3,而没有定义任何结构体类型。

该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 3 {Andreah Nikola 31 5000}

结构体的零值(Zero Value)

当定义好的结构体并没有被显式地初始化时,该结构体的字段将默认赋为零值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    var emp4 Employee //zero valued structure
    fmt.Println("Employee 4", emp4)
}

该程序定义了 emp4,却没有初始化任何值。因此 firstNamelastName 赋值为 string 的零值("")。零值是对应类型的零值。 而 agesalary 赋值为 int 的零值(0)。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 4 { 0 0}

当然还可以为某些字段指定初始值,而忽略其他字段。这样,忽略的字段名会赋值为零值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp5 := Employee{
        firstName: "John",
        lastName:  "Paul",
    }
    fmt.Println("Employee 5", emp5)
}

在上面程序中的第 14 行和第 15 行,我们初始化了 firstNamelastName,而 agesalary 没有进行初始化。因此 agesalary 赋值为零值。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 5 {John Paul 0 0}

访问结构体的字段

点号操作符 . 用于访问结构体的字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp6 := Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", emp6.firstName)
    fmt.Println("Last Name:", emp6.lastName)
    fmt.Println("Age:", emp6.age)
    fmt.Printf("Salary: $%d", emp6.salary)
}

上面程序中的 emp6.firstName 访问了结构体 emp6 的字段 firstName。该程序输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam  
Last Name: Anderson  
Age: 55  
Salary: $6000

还可以创建零值的 struct,以后再给各个字段赋值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    var emp7 Employee
    emp7.firstName = "Jack"
    emp7.lastName = "Adams"
    fmt.Println("Employee 7:", emp7)
}

在上面程序中,我们定义了 emp7,接着给 firstNamelastName 赋值。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 7: {Jack Adams 0 0}

结构体的指针

还可以创建指向结构体的指针。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", (*emp8).age)
}

在上面程序中,emp8 是一个指向结构体 Employee 的指针。(*emp8).firstName 表示访问结构体 emp8firstName 字段。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam
Age: 55

Go 语言允许我们在访问 firstName 字段时,可以使用 emp8.firstName 来代替显式的解引用 (*emp8).firstName

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", emp8.firstName)
    fmt.Println("Age:", emp8.age)
}

在上面的程序中,我们使用 emp8.firstName 来访问 firstName 字段,该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam
Age: 55

匿名字段

当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。

以下代码创建一个 Person 结构体,它含有两个匿名字段 stringint

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Person struct {  
    string
    int
}

我们接下来使用匿名字段来编写一个程序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Person struct {  
    string
    int
}

func main() {  
    p := Person{"Naveen", 50}
    fmt.Println(p)
}

在上面的程序中,结构体 Person 有两个匿名字段。p := Person{"Naveen", 50} 定义了一个 Person 类型的变量。该程序输出 {Naveen 50}

虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。比如在上面的 Person 结构体里,虽说字段是匿名的,但 Go 默认这些字段名是它们各自的类型。所以 Person 结构体有两个名为 stringint 的字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Person struct {  
    string
    int
}

func main() {  
    var p1 Person
    p1.string = "naveen"
    p1.int = 50
    fmt.Println(p1)
}

在上面程序中,我们访问了 Person 结构体的匿名字段,我们把字段类型作为字段名,分别为 "string" 和 "int"。上面程序的输出如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{naveen 50}

嵌套结构体(Nested Structs)

结构体的字段有可能也是一个结构体。这样的结构体称为嵌套结构体。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Address struct {  
    city, state string
}
type Person struct {  
    name string
    age int
    address Address
}

func main() {  
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.address = Address {
        city: "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:",p.age)
    fmt.Println("City:",p.address.city)
    fmt.Println("State:",p.address.state)
}

上面的结构体 Person 有一个字段 address,而 address 也是结构体。该程序输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

提升字段(Promoted Fields)

如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。我知道这种定义很复杂,所以我们直接研究下代码来理解吧。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Address struct {  
    city, state string
}
type Person struct {  
    name string
    age  int
    Address
}

在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。现在结构体 Addresscitystate 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
)

type Address struct {
    city, state string
}
type Person struct {
    name string
    age  int
    Address
}

func main() {  
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.Address = Address{
        city:  "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.city) //city is promoted field
    fmt.Println("State:", p.state) //state is promoted field
}

在上面代码中的第 26 行和第 27 行,我们使用了语法 p.cityp.state,访问提升字段 citystate 就像它们是在结构体 p中声明的一样。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

导出结构体和字段

如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。同样,如果结构体里的字段首字母大写,它也能被其他包访问到。

让我们使用自定义包,编写一个程序来更好地去理解它。

在你的 Go 工作区的 src 目录中,创建一个名为 structs 的文件夹。另外在 structs 中再创建一个目录 computer

computer 目录中,在名为 spec.go 的文件中保存下面的程序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package computer

type Spec struct { //exported struct  
    Maker string //exported field
    model string //unexported field
    Price int //exported field
}

上面的代码片段中,创建了一个 computer 包,里面有一个导出结构体类型 SpecSpec 有两个导出字段 MakerPrice,和一个未导出的字段 model。接下来我们会在 main 包中导入这个包,并使用 Spec 结构体。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import "structs/computer"  
import "fmt"

func main() {  
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    fmt.Println("Spec:", spec)
}

包结构如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
src  
   structs
        computer
            spec.go
        main.go

在上述程序的第 3 行,我们导入了 computer 包。在第 8 行和第 9 行,我们访问了结构体 Spec 的两个导出字段 MakerPrice。执行命令 go install structsworkspacepath/bin/structs,运行该程序。

如果我们试图访问未导出的字段 model,编译器会报错。将 main.go 的内容替换为下面的代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import "structs/computer"  
import "fmt"

func main() {  
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    spec.model = "Mac Mini"
    fmt.Println("Spec:", spec)
}

在上面程序,我们试图访问未导出的字段 model。如果运行这个程序,编译器会产生错误:spec.model undefined (cannot refer to unexported field or method model)

结构体相等性(Structs Equality)

结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type name struct {  
    firstName string
    lastName string
}


func main() {  
    name1 := name{"Steve", "Jobs"}
    name2 := name{"Steve", "Jobs"}
    if name1 == name2 {
        fmt.Println("name1 and name2 are equal")
    } else {
        fmt.Println("name1 and name2 are not equal")
    }

    name3 := name{firstName:"Steve", lastName:"Jobs"}
    name4 := name{}
    name4.firstName = "Steve"
    if name3 == name4 {
        fmt.Println("name3 and name4 are equal")
    } else {
        fmt.Println("name3 and name4 are not equal")
    }
}

在上面的代码中,结构体类型 name 包含两个 string 类型。由于字符串是可比较的,因此可以比较两个 name 类型的结构体变量。

上面代码中 name1name2 相等,而 name3name4 不相等。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
name1 and name2 are equal  
name3 and name4 are not equal

如果结构体包含不可比较的字段,则结构体变量也不可比较。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type image struct {  
    data map[int]int
}

func main() {  
    image1 := image{data: map[int]int{
        0: 155,
    }}
    image2 := image{data: map[int]int{
        0: 155,
    }}
    if image1 == image2 {
        fmt.Println("image1 and image2 are equal")
    }
}

在上面代码中,结构体类型 image 包含一个 map 类型的字段。由于 map 类型是不可比较的,因此 image1image2 也不可比较。如果运行该程序,编译器会报错:main.go:18: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.04.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误
崔庆才
2017/03/14
4.5K0
腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误
ubuntu12.04安装python3
默认系统已经自带了python2.7。在安装python3.5的时候,不要将python2.7的版本删掉,因为系统本身有很多功能都是需要python2.7的支持。可以通过vitrualenv工具,给不同python版本做环境隔离,应该就可以让不同版本的python共存了。其实,在安装python3.5的时候,注意配置一下安装路径,重新建立软链接就能很好地区分python2.7和3.5了,不需要用到vitrualenv。
py3study
2020/01/03
1.1K0
【scrapy】debian下scrapy的安装
1.(sudo) apt-get update && apt-get upgrade -y && apt-get install python-pip -y 安装pip
蛮三刀酱
2019/03/26
6200
scrapy安装步骤_scrapy安装教程
Scrapy的安装有多种方式,它支持Python2.7版本及以上或Python3.3版本及以上。下面说明Python3 环境下的安装过程。 Scrapy依赖的库比较多,至少需要依赖库有Twisted 14.0,lxml 3.4,pyOpenSSL 0.14。而在不同平 台环境又各不相同,所以在安装之前最好确保把一些基本库安装好,尤其是Windows。
全栈程序员站长
2022/10/02
3.9K0
scrapy安装步骤_scrapy安装教程
Scrapy在Ubuntu下的安装与配置
Scrapy在Ubuntu下的安装与配置 吐槽一下 最近几天由于比较忙,关于Torch7剩下的部分过些日子再更新。现在想想,是不是好久没有更行python爬虫的东西啦?好的吧,今天由于台式机的Ubuntu崩溃了,不得不重新安装Scrapy爬虫框架,正好姐这个机会写点关于Scrapy在Ubuntu下的安装与配置的相关内容吧。说实话,在Ubuntu下安装SCrapy比在Window下安装方便多了(window下的安装教程度娘一搜一大把不再赘述)。 1 安装python sudo apt-get install
昱良
2018/04/08
1.2K0
Scrapy在Ubuntu下的安装与配置
在Ubuntu 18.04 LTS上安装Python 3.7
Python是最受欢迎和随需应变的通用编程语言之一。它是一种解释性的高级编程语言,支持多种编程范例,包括过程式,面向对象和函数式编程。由于其全面的标准库,它通常被描述为“py自带着电池”。
用户6543014
2020/04/02
6.6K0
ubuntu创建pytorch-gpu的docker环境
vim先按Esc,然后输入:wq回车,保存退出,生怕你们linux不好(doge。
唔仄lo咚锵
2024/01/05
4640
ubuntu创建pytorch-gpu的docker环境
ubuntu上使用python3安装第三
  使用jenkins管理我的python代码,因为使用的是python3.5的版本,先在ubuntu上使用virtualenv生成一个python3.5的虚拟运行环境                             
py3study
2020/01/03
6870
ubuntu上使用python3安装第三
如何在Ubuntu 14.04上使用Python3安装和配置Riak2
Riak是一个noSQL非关系数据存储区,专注于分布式数据库架构。使用最新的Riak 2.1.1版本,可以使所有数据保持一致,其中数据在检索时是最新的,而不是最终一致的,其中数据更易于访问但不是最新的。
小翼111
2018/09/29
8160
linux下安装Python3.6
sudo sed -i 's\archive.ubuntu.com\mirrors.aliyun.com\g' /etc/apt/sources.list sudo apt-get update cd /home/ sudo apt-get install gcc make zlib1g-dev -y sudo apt-get install libbz2-dev libsqlite3-dev libxml2-dev libffi-dev libssl-dev -y sudo apt install
小歪
2018/07/25
7350
Docker学习总结之docker安装 (因为Ubuntu的安装过程类似,我们只以一个版本的安装为例)  Ubuntu Trusty 14.04 (LTS) (64-bit)
Ubuntu安装指南 以下均翻译自Docker官方文档 ,转载请注明:Vikings翻译   Docker 支持多种平台下的安装运行,现在我们选取结合度最高的ubuntu来说明安装过程。   首先需要明确Docker支持的ubuntu版本:   Ubuntu Trusty 14.04 (LTS) (64-bit)   Ubuntu Precise 12.04 (LTS) (64-bit)   Ubuntu Raring 13.04 and Saucy 13.10 (64 bit)  目前Docker仅
随机来个数
2018/04/16
8730
多python环境下使用pip安装包
笔记本上安装了2.7和3.5两个版本的python,在使用3.5版本的pip安装keras时出现了failed to create process错误。解决方法如下: 1.由于我在环境变量中同时配置了2.7和3.5的路径,所以我可以直接在命令行下执行python3来启动3.5版本的python; 2.通过python3来启动pip,在命令行中输入python3 -m pip install keras,成功安装上keras。
py3study
2020/01/08
2K0
Ubuntu安装docker
参考官方安装地址:https://docs.docker.com/engine/install/ubuntu/
是小张啊喂
2022/08/18
2.7K0
AI树莓派——构建树莓派大脑(NCNN环境搭建)
https://pan.baidu.com/s/1fhiX86L8iL8tsLbsiVa6Wg 密码: e64s
AI异构
2020/07/29
2.2K0
AI树莓派——构建树莓派大脑(NCNN环境搭建)
ubuntu14.04.1升级openssh
由于ubuntu14.04.1默认的openssh是5.6p1版的,有很多安全漏洞,所以计划升级至openssh7.5p1 一、下载升级所需的软件 zlib-1.2.11.tar.gz openssh-7.5p1.tar.gz openssl-1.0.2l.tar.gz
孙杰
2019/10/29
1.6K0
ubuntu14.04.1升级openssh
SmartRobotControlPlateform——智能机器人控制平台(新)
19年初的时候在实验室终于搞定了自己的一套树莓派的嵌入式管理平台,实现了对履带式坦克机器人的控制以及之智能家传感器的管理,由于之前开发的平台还是基于18年的raspbian(搭建过程如下:SmartRobotControlPlateform——智能机器人控制平台),最近家里的4B一直空着,必须让它发光发热,决定重新在4b 上搭建一套嵌入式平台,搭建过程中发现有些库换了,因此,记录下基于2021-05-07-raspios-buster-armhf的4B搭建过程。
墨文
2021/06/29
1.3K0
Ubuntu16升级Python3
网上好多Ubuntu16.04升级Python的方法,但是大多教程都是使用源码安装的方式。这篇博文将会使用另一种方法将系统自带的Python3.5升级到Python3.6。 用过Ubuntu16.04的人都知道,这个版本Ubuntu的软件源安装列表中是没有Python3.6的安装包的,所以我们需要添加安装源,在命令行输入如下命令:
喵叔
2020/09/08
1.5K0
在Ubuntu下安装单细胞3大R包
通常来说,很多R包的安装对R版本是有要求的,比如BiocManager需要 R (≥ 3.5.0),但是并不需要最新版R语言。
生信技能树
2019/07/26
2.5K0
linux上安装python3, 保留python2
首先, linux系统中自带python2, 所以可以直接使用python命令, 注意, 安装python2不能卸载
cg错过
2020/11/25
2.1K0
linux上安装python3, 保留python2
如何使用Passenger和Nginx部署Rails
如果您是Ruby on Rails开发人员,可能需要Web服务器来托管您的Web应用程序。本教程将向您展示如何使用Phusion Passenger。作为Rails的Web服务器,Passenger易于安装,配置和维护,可与Nginx或Apache一起使用。在本教程中,我们将在Ubuntu上安装带有Nginx的Passenger。
乌鸦
2018/08/06
5.6K0
如何使用Passenger和Nginx部署Rails
推荐阅读
相关推荐
腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验