Go 基础语法1(语法、指针、结构体、接口)

1. 环境搭建;

下载地址:https://golang.google.cn/dl/

# 下载安装包
cd /usr/local/src
wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz

# 解压
tar zxvf go1.14.2.linux-amd64.tar.gz

# 拷贝到 /usr/local 下
mv /usr/local/src/go /usr/local

# 配置环境变量
# macos:vim ~/.bash_profile
vim /etc/profile.d/go.sh
# 写入以下内容
# GOROOT:go 安装文件的路径
# * GOPATH:go 的一些工具或下载,import包都会用到这个目录
# 比如 import "某包",在 GOROOT 里没有,就会去 GOPATH 去寻找
# 然后手动创建以下三个目录
# src 存放源代码(各种文件夹、.go 等)
# pkg 编译时生成的中间文件(比如:.a)
# bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,也可以不加)
export GOPATH=/Users/go
export GOROOT=/usr/local/go
export PATH=$PATH:$GOPATH/bin:$GOROOT/bin

# 保存退出,使其生效
source /etc/profile.d/go.sh

# 验证安装
go version
# 返回如下,搞定
go version go1.14.2 linux/amd64

操作

  • 创建项目文件夹和代码文件
# src 文件夹下创建项目文件夹的代码文件
mkdir -p /Users/go/src/mygo
vim /Users/go/src/mygo/index.go
  • 编写 /Users/go/src/mygo/index.go
// 类似于 php 的 namespace
package main

// 引入系统包
import "fmt"

// 入口函数
func main() {
	fmt.Print("hello world")
}

运行

# 项目目录运行
cd /Users/go/src/mygo/
go run index.go
# 输出:hello world

# go build 运行
go build
# 没有输出,在同级目录生成了一个可执行程序 mygo.exe(目录名称)

# go install 运行
go install
# /Users/go/src/mygo/mygo.exe 消失
# /Users/go/bin/ 目录下生成了 mygo.exe,可以直接进入目录执行

2. 语法套路:类型、定义函数、返回值;

类型,主要分

  1. 基本类型(数字,字符串,布尔类型)
  2. 复合类型(数组 Array,结构 struct )
  3. 引用类型(指针,切片,函数、通道)
  4. 接口类型

字符串

// 使用 var 定义变量
var str string
str = "abc"

//定义变量,并指明类型,同时赋值
var str string = "abc"

// string 可以去掉,系统会自动推断类型
var str = "abc"

// 定义变量,并赋值,系统会自动推断类型
// 只能在函数内使用
str := "abc"   

函数
在这里插入图片描述

// 一般函数
func getMe() string {
	return "lisi"
}

// 支持参数
func getMe(prefix string) string {
	return prefix + "lisi"
}

// 返回多个值
// main 函数不能有参数,也不能有返回值
func main() {
	var name,age = getMe("程序员")  
	fmt.Println(name)
	fmt.Println(age)
}

func getMe(prefix string) (string, int) {
	return prefix + "lisi", 19
}

// 综合
func getMe(prefix , address string) (string, int) {
	// 参数的定义方式类似: var abc,bcd string
	name := prefix + "lisi " + address
	age := 24
	return name, age
}

func main() {
	// 写法 1:
	fmt.Println(getMe("Student ", "live in BJ"))
	// 返回 Student lisi live in BJ 24
	
	// 写法 2:
	var a,b = getMe("Student ", "live in BJ")
	// a 对应返回的第一个 string 参数对应 name, b 返回 int 参数对应 age
	fmt.Println(a)
	fmt.Println(b)
	// 返回
	// Student lisi live in BJ
	// 24
}

3. 包引用、“实体类”使用(struct);

包最直观的的作用就是协调和组织代码,方便归类和复用,提高代码的可维护性

3.1 使用包;

# 首先在的 GOPATH 的 src 下创建一个文件夹,比如叫 com.test(建议 xxx.xx.xx)
cd /Users/go/src/
# 创建顶级包
mkdir com.test

# 接下来用 Goland 的直接打开 src 目录 (注意是直接打开 src,而不是下面的包)
# 打开 /Users/go/src/com.test
# 再创建子包 services(创建服务:用户、新闻相关业务逻辑服务)
mkdir /Users/go/src/com.test/services
touch /Users/go/src/com.test/services/UserService.go
touch /Users/go/src/com.test/services/NewsService.go

# 接下去运行,需要一个入口函数 / 包
# 创建文件夹 appmain,专门放入口函数
mkdir /data/go/src/com.test/appmain
touch /data/go/src/com.test/appmain/main.go

文件 /Users/go/src/com.test/services/NewsService.go

package services

func GetNews()  string {
	return "news info "
}

文件 /data/go/src/com.test/services/UserService.go

// 如果在文件夹里创建 .go 文件,默认 package [文件夹名]
package services
// package 名称是否要和文件夹名称一样?不一定
// package abc:会报错"在一个文件夹内不能出现不同包名"
// 想要不报错,把其它文件的 package 也改成 abc
// 但是一般情况下 package 会创建成个文件夹一样的名字,方便代码阅读和维护

func GetUser() string {
	// 在 UserService 调用 NewsService
	// 同包调用:不需要 import,直接调用
	// 同一个包,函数名不能冲突
	news := GetNews()
	return "user info " + news
}

文件 /Users/go/src/com.test/appmain/main.go

// package appmain
// 和之前的 package appmain 不一样

// 之前写的入口文件有两个关键点
// 第一是 package,是个特殊的 package, 它本身就是个 main 包
package main

import (
	// 这里的包引用是文件夹路径
	// 就算把 UserService 的导包改成 package abc,这里依然不变
	"com.test/services"
	// 在 /usr/local/go/src/ 下有 fmt 文件夹,里面有相关函数,比如 print
	"fmt"
)

func main()  {
	// 异包调用函数,异包的函数首字母大写:getUser() 改成 GetUser()
	// 这里的应用和包名有关系
	// 如果异包的包名改成了 package abc。这里就是 abc.GetUser()
	result := services.GetUser() +
		services.GetNews()

	fmt.Print(result)
	// 输出:user info news info news info

}

3.2 Go 的“实体类”;

# golang 不像 java 或PHP,有 class 类等面向对象的概念
# 一般可以使用 struct 来实现类似的感觉
type User struct {
	 Uid int
	 Uname string
}
# 这好比有个类叫做 User,里面有两个属性 uid 和 uname, 也没有 public、protected、private 修饰符

创建文件 /Users/go/src/com.test/models/UserModel.go

package models

// 创建结构体
// 如果要外包调用,首字母必须大写
type UserModel struct {
	// 外包调用结构体
	// 属性必须首字母大写才能被调用
	Uid int
	Uname string
}

// u 是一个参数
// ToString 是方法名
// 返回 string 类型
// 相当于一个类方法
func (u UserModel) ToString() string {
	return "用户名是 " + u.Uname
}

// 无效方法,之后说明
func (u UserModel) SetValue(id int, name string) {
	// 修改值不会修改所指向的内存,所以修改无效
	// 如果要修改 UserModel 改为 *UserModel
	u.Uname = name
	u.Uid = id
}

// 这是一个纯函数
func ToString() string  {
	return "测试字符串 "
}

文件 /data/go/src/com.test/services/UserService.go

package services

import "com.test/models"

func GetUser() string {
	// 调用结构体
	user := new(models.UserModel)
	user.Uname = "Jerry "
	// 修改无效
	user.SetValue(123, "Tom")
	return user.ToString()
}

文件 /Users/go/src/com.test/appmain/main.go 调用,返回结果:用户名是 Jerry

4. 指针类型;

在这里插入图片描述
概念

  • 每个座位就是一个内存,由系统开辟。如果不开辟,椅子是没有的
  • 每个椅子后面的编号(三排一座、三排二座)这些好比就是内存地址。切换到计算机,就是十六进制的字符(比如:0xc03201b1a2)
  • 椅子上可能会坐人,坐在上面的人就是数据
  • 标签“局长专座” 就是定义的变量
    • 内存地址(椅子后面的编号比如:三排一座)指向内存空间(某一个椅子),内存空间有数据(椅子上坐的一个人)、会放什么值
    • 如何操作地址和如何获取、如何对内存开辟?比如电影院有八个位置,由于人比较多,不得不再增加一个位置,于是在电影院再放一张椅子,这就是开辟内存。开辟内存有了椅子之后,一定要写上一个标签,比如二排四座,这就是内存地址
    • 有个“局长专座”。之前要坐位置,需要找到“几排几座”,找到位置坐下来。但是有的位置是领导坐的,只能是领导坐的,所以会在椅子上再去贴上一个标签比如“局长专座”,以后要找局长,直接就去找“局长专座”的标签的位置。如果硬要和程序对应,就定义为“变量”,“变量”就是贴上去的标签
    • 变量、内存地址和内存之间的映射是由相关的程序进行实现的

直接去记内存地址(0xc03201b1a2)是很麻烦的,也不可能这么做。所以很多高级语言会有:变量,并且隐藏了内存地址和变量之间的映射关系

// 定义字符串变量,这里的 name 就相当是“局长专座”
// 电影院一张椅子已经贴上了“局长专座”的标签,已经有地址(内存地址)了
// 在这行代码里看不到类似“0xc03201b1a2”,已经隐藏了内存地址
// 只需要对标签赋值
// 这时候内存地址是不知道的
name := "Jerry"

// 如果需要看一下内存地址(几排几座)的话
// 加“&”,就可以获得地址
// 有时候局长会在电影院里调整座位,内存地址会发生变化
// 但是标签和值在代码里的展示部分是不会有变化的
fmt.print(&name)

// 已经知道了地址,比如 0x12d492d,想获取坐在上面的人是谁
//这就是取值的过程
name:="Jerry"
// 先取地址,后取值
fmt.Print(*&name)
// 输出 Jerry
// “*” 符号好比起到了取值的作用。
// “&” 取地址
// 上面两者互为反操作
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import "fmt"

func main()  {
	// 定义一个标签叫 name,也就是变量,坐上去的这个人就是 Jerry,就是数据
	// 这时候内存地址是不知道的
	var name string="Jerry"

	// 输出 Jerry
	fmt.Print(name)

	// 返回内存地址
	// 没有任何可理解的业务意义,一般不会对内存地址进行直接操作
	// 输出 0xc000010200 (每次输出可能会不一样)
	fmt.Print(&name)
	
	// 取地址的值
	// 返回值:输出 Jerry
	fmt.Print(*&name)
}

指针类型

 普通变量
// 拥有地址,系统已经开辟了内存,只不过是空字符串
// 好比电影院已经有了位置和地址(几排几座),但是座位上的人不在
var name string
// 返回空
fmt.Println(name)

 定义指针类型
// 未初始化指针变量是 nil,内存还没有开辟空间
// 好比领导告诉电影院管理员,需要加一个位置,所以管理员准备加一个位置
// 实际上椅子还没有搬过来,椅子上是几排几座也不知道
// 这里的 name 就是地址(几排几座),标签(局长专座)
var name *string;
// 返回<nil>
fmt.Println(name)
// 怎么让变量有,这时候就要去买椅子
// 开辟内存的过程就是领导让电影院管理员去购买椅子

// 使用关键词 new 开辟内存并且返回内存地址
// 开辟内存,并返回内存地址,于是 name 这个指针变量就有内存地址了
// 这个过程就好比有了一个座位,有座位就可以往电影院随便放,就可以获取位置了(几排几座)
name = new(string)
// 不能 name = "Jerry",因为 name 是内存地址/地址、标签(几排几座),不可能让人坐在标签上
// 取值是 *name ,赋值也得加“*”
*name = "Jerry"
	
// 返回内存地址
fmt.Println(name)
// 返回值
// *name 取值,取座位上的人、或者指向另外一个座位
fmt.Println(*name)
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import "fmt"

func main()  {
	// 定义指针变量
	var name *string

	// 开辟内存空间赋值给指针,指针就有内存地址了
	name = new(string)

	// 赋值
	*name = "Jerry"
	
	// 取值
	fmt.Println(*name)
}

5. 函数及参数传递;

示例 1

package main

import "fmt"

func main()  {
	// 定义变量
	var me string = "Jerry"
	// 定义指针变量,没有初始化,之后设置成 me 所在的地址
	// 现在已经存在是一个内存块,有 me 的值
	var u *string
	// u 赋值给 me 的地址
	// 在指针变量里,设置地址只要直接写变量
	// 普通变量,取地址需要在前面加“&”,取值要加“*”
	u = &me
	// 地址一样,输出 Jerry Jerry
	fmt.Println(me, *u)
	
	// 任意修改其中一个值
	// 指针变量 u 设置为 me 的地址,因此只要 “改变” me 的值
	// 则 u 的值也会改变
	// me 改掉,
	// me = "Tom",等于把 me 所在的指针地址指向一个新的内存块,块的值就是 Tom
	// u 的值也发生了改变
	me = "Tom"
	// 输出 Tom Tom
	fmt.Println(me, *u)
	// 注意:字符串是不可变的。修改字符串值不是把原有的值给改了,只不过是指针的指向
	// 在并发操作中,如果直接在原对象值上改,会出现线程不安全
	// 现在这样操作是直接产生一个新对象,然后把指针指向新对象,就不需要加锁
	
	// 指向新的内存对象
	*u= "Perry"
	// 输出 Perry Perry
	fmt.Println(me, *u)
}

示例 2

package main

import "fmt"

func main()  {
	// 定义变量
	var me string = "Jerry"
	fmt.Println(me)		// Jerry
	// 向函数传递 me 所指向的值
	// 修改值不会修改 me 所指向的内存
	// 所以在 test() 函数里修改 p 的值 没有任何变化
	test1(me)
	fmt.Println(me)	// Jerry

	// 传地址
	test2(&me)
	fmt.Println(me)	// abc
}

func test1(p string) {
	// 指向新内存,值为 abc
	p = "abc"
}

// 如果需要让 main 函数里的 me 产生变化
// test2() 的 p 参数设置为指针
func test2(p *string) {
	// 把所指向的值给改了,并不是改指针
	// 指向到了 abc
	*p = "abc"
}

// 输出 Jerry Jerry abc

示例 3

package main

import "fmt"

func main()  {
	// 定义指针变量
	u := new(string)
	*u = "Stark"
	
	// 打印值:Stark
	fmt.Println(*u)
	// 打印地址:0xc000010200
	fmt.Println(u)

	// 传地址 u,*u 是传值
	test2(u)
	fmt.Println(*u)	// abc

	test3(u)
	// 输出指针变量 u 的地址
	// 指针地址没有发生变化

	// 之前使用普通变量,按值传递
	// 传指针,也是传的是"指针所指向的值",并没有把指针给改掉
	fmt.Println(u)	// 0xc000010200

}

// 如果需要让 main 函数里的 me 产生变化
// test2() 的 p 参数设置为指针
func test2(p *string) {
	// 把所指向的值给改了,并不是改指针
	// 指向到了 abc
	*p = "abc"
}

func test3(p *string) {
	// 把指针地址改成 nil
	// 在指针没有进行初始化的时候,它的值就是 nil
	p = nil
}

// 输出
// Stark
// 0xc000010200
// abc
// 0xc000010200

6. 结构体;

6.1 设置一个实体类、初始化;

在 Go 中实现类似 OOP 的功能使用结构体:可以把结构体看做是一堆应该放在一起才更有意义的 类型集合

// 在其它语言中就是一个实体类
package main

import "fmt"

type NewsModel struct {
	NewsID int
	NewsTitle, NewsContent string
}

func main()  {
	// 初始化方式 1
	// 变量初始化,类型是 NewsModel
	// 类似 var abc string
	// 结构体已经在 var 的时候已经在内存了开辟了空间
	// 对成员结构进行了初始化,只不过是 0 值
	var news NewsModel
	// 赋值
	news.NewsID = 123
	news.NewsTitle = "title"
	// 没有赋值的时候,打印返回 {0  }, 0 就是 int,空就是两个 string
	// 结构体可以直接打印,根据一定的格式显示
	fmt.Println(news)	// {123 title }

	// 初始化方式 2:定义的时候直接初始化
	// var news2 NewsModel = NewsModel{123,"title", "content"}
	// news2 := NewsModel{123,"title","content"}
	news2 := NewsModel{NewsTitle: "title2", NewsID: 11}
	fmt.Println(news2)	// {11 title2 }

	// 初始化方式 3:指针方式
	var news3 *NewsModel
	news3 = new(NewsModel)
	// 设置值
	// (*news3).NewsID = 233
	news3.NewsTitle = "news3title"
	// 取出来的是值 news3title,而不是地址
	fmt.Println(news3.NewsTitle)
	// 结构体内部,成员变量的地址 0xc0000901e8
	fmt.Println(&(news3.NewsTitle))

	// 指针变量初始化,参数需要写全
	*news3 = NewsModel{1344,"news4title", "news4content"}
	// news3 = &NewsModel{1344,"news4title", "news4content"}
	fmt.Println(news3)	// &{1344 news4title news4content}
}

6.2 使用第三方包、JSON 化结构体;

使用第三方包、避免重复造车轮

# 下载包
go get -u github.com/pquerna/ffjson
# 除了 github 还能从自己的 git 中导入的包并编译(中间文件),会保存在 gopath 的第一个工作区中
# -u :如果本地已经存在该包,则依然强行更新

示例

package main

import (
	"fmt"
	"github.com/pquerna/ffjson/ffjson"
)

type NewsModel struct {
	NewsID int
	NewsTitle string
}

// 定义方法
func (news NewsModel) ToJSON() (string) {
	result, err := ffjson.Marshal(news)
	if err != nil {
		// fmt.printIn(err.Error())
		return err.Error()
	} else {
		// 字节数组转 string
		// 返回 {"NewsID":123,"NewsTitle":"title"}
		return string(result)
	}
}

func main()  {
	news := NewsModel{123, "title"}
	fmt.Println(news.ToJSON())
}

// 如果将以上结构体单独写入类 /Users/go/src/com.test/models/NewsModel.go
// 则调用方式:
// news := models.NewsModel{NewsID: 123, NewsTitle: "title", NewsContent: "content"}

// var news models.NewsModel
// news.NewsID = 1
// news.NewsTitle = "title"

// fmt.Println(news.ToJSON()) 

6.3 继承、数组;

Go 没有 extends、implements 等关键字,但是依然可以使用一些方式来完成面向对象编程里的继承:结构体嵌套

  • 母类 /Users/go/src/com.test/models/NewsModel.go
package models

import "github.com/pquerna/ffjson/ffjson"

type NewsModel struct {
	NewsID int
	NewsTitle string
}

// 定义方法
func (news NewsModel) ToJSON() string {
	result, err := ffjson.Marshal(news)
	if err != nil {
		return err.Error()
	} else {
		return string(result)
	}
}
  • 子类继承母类 /Users/go/src/com.test/submodels/SportsNews.go
package submodels

import (
	"com.test/models"
	"github.com/pquerna/ffjson/ffjson"
)

type SportsNews struct {
	Tags []string	// array
	// 下面这种写法只是结构体的组合,并不实现继承功能
	// News models.NewsModel
	// 在 main() 方法中 
	// var sn submodels.SportsNews
	// sn.News.NewsID 只能用过类寻找到变量

	// 下面这种写法只有类型(NewsModel 类型),不加入任何名称,是匿名的
	// 这样就可以实现继承的感觉
	models.NewsModel
	// sn.NewsID = 123
	// sn.NewsTitle = "title"
	// fmt.Println(sn.ToJSON())
}

// 覆盖母类的方法,就直接执行子类的方法
func (sn SportsNews) ToJSON() string {
	result, err := ffjson.Marshal(sn)
	if err != nil {
		return err.Error()
	} else {
		return string(result)
	}
}
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import (
	"com.test/submodels"
	"fmt"
)

func main()  {
	// 调用结构体
	//news := models.NewsModel{123,"title"}
	//fmt.Println(news.ToJSON())

	// 1. 继承调用
	var sn submodels.SportsNews
	sn.NewsID = 112233
	sn.NewsTitle = "BigNewsTitle"
	sn.Tags = []string{"足球", "篮球", "游泳"}
	// 打印返回 {"NewsID":112233,"NewsTitle":"BigNewsTitle"}
	// 执行母类的 ToJSON() 方法, tags 没有打印出来
	// 子类方法覆盖后,返回 
	// {"Tags":["足球","篮球","游泳"],"NewsID":112233,"NewsTitle":"BigNewsTitle"}
	fmt.Println(sn.ToJSON())

	// *2. 数组的使用
	// var arr []int
	// var arr []models.NewsModel
	var arr []string = []string{"a", "b", ""}
	fmt.Println(arr, len(arr))	// [a b ] 3

	// 先设定数组长度
	// 数组长度设定后,不能改变
	var arr2 [3]string
	arr2[0] = "aa"
	arr2[2] = "cc"
	fmt.Println(arr2)	// [aa  cc]

	// 对索引进行赋值
	var arr3 [3]string = [3]string{0:"aaa", 2: "ccc"}
	fmt.Println(arr3)	// [aaa  ccc]
	
	// 对数组进行操作,要用到切片

}

7. interface 接口;

7.1 实现接口,简单工厂模式;

  • 新增 /Users/go/src/com.test/services/IService.go ,专门放服务接口
package services

// 把代码抽象到 interface 里
type IService interface {
	Get (id int) (string)
}
  • 新增 /Users/go/src/com.test/services/NewsService.go ,专门放服务接口
package services

type NewsService struct {
}

// 普通写法: func (ns NewsService) Get(id int) (string)  {
// 指针写法:
func (ns *NewsService) Get(id int) (string)  {
	return "单个新闻内容"
}
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import (
	"com.test/services"
	"fmt"
)

func main()  {
	// 前面是接口,后面是具体的实现类
	//var service services.IService = services.NewsService{}
	var service services.IService = new(services.NewsService)	// 此写法兼容指针调用
	fmt.Println(service.Get(123))
}

7.2 简单工厂模式;

  • 设计模式中:工厂模式有几种类型(简单工厂、工厂方法、抽象工厂)

  • 基本特征:掩盖 new 过程;会有一个工厂类,且一般会有个方法接受参数,根据参数来决定实例化什么类

  • 可能损耗一些性能,但是可维护性高

  • /Users/go/src/com.test/services/IService.go

package services

// 工厂模式
type ServiceFactory struct {
}

// 普通方法
func NewsServiceFactory() (*ServiceFactory) {
	return &ServiceFactory{}
}

func (sf ServiceFactory) Create(name string) (IService) {
	switch name {
		case "news":
			return &NewsService{}
		case "user":
			return &UserService{}
		default:
			return nil
	}
}
  • /Users/go/src/com.test/services/NewsService.go
package services

type NewsService struct {
}

// 指针写法:
func (ns *NewsService) Get(id int) (string)  {
	return "单个新闻内容"
}
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import (
	"com.test/services"
	"fmt"
)

func main()  {
	// 工厂调用
	// 调用方法1:(不推荐)
	var sevice11 services.IService = new(services.ServiceFactory).Create("news")
	fmt.Println(sevice11.Get(123))

	// 调用方法2:
	var sevice22 services.IService = services.NewsServiceFactory().Create("news")
	fmt.Println(sevice22.Get(123))
}

7.3 包构造函数、自动注册接口(代码技巧);

调整结构:

  • 新增 /Users/go/src/com.test/core/IService.go
package core

type IService interface {
	Get (id int) (string)
}

// init
var myService IService

func SetService(service IService) {
	myService = service
}

func GetService() (IService) {
	return myService
}

新增 /Users/go/src/com.test/services/ServiceFactory.go

package services

import "com.test/core"

// 工厂模式
type ServiceFactory struct {

}

// 普通方法
func NewsServiceFactory() (*ServiceFactory) {
	return &ServiceFactory{}
}

func (sf *ServiceFactory) Create(name string) (core.IService) {
	switch name {
	case "news":
		return &NewsService{}
	case "user":
		return &UserService{}
	default:
		return nil

	}
}

// 写了 init() 函数后 ,main() 函数就不需要写 SetService
func init()  {
	core.SetService(NewsServiceFactory().Create("news"))
}
  • 文件 /Users/go/src/com.test/appmain/main.go
package main

import (
	"com.test/core"
	_ "com.hua/services"	// 可前置加 s 为别名,加 "_” 为不调用
	// . "com.test/services"	// 改成”.“,调用就不需要前缀
	"fmt"

)

// 入口函数 main()
// 还有 init() 函数(包函数),能够应用于所有的 package,可以有多个,均会执行,不可以有参数和返回值

// main() 函数引入包时,
//(1)初始化包常量(变量);
//(2)执行包内 init() 函数;
// (3) 执行 main() 函数
func main()  {
	var sevice core.IService = services.NewsServiceFactory().Create("news")
	fmt.Println(sevice.Get(123))
	
	// 调用
	core.SetService( services.NewsServiceFactory().Create("news"))
	fmt.println(core.GetService().Get(123))
	
	// 不需要抵用 SetService(),因为已经写了 init() 函数
	fmt.Println(core.GetService().Get(123))
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值