zl程序教程

您现在的位置是:首页 >  其他

当前栏目

结构体/接口

接口 结构
2023-09-27 14:19:41 时间

一.struct(结构体)

go中的struct可以实现oop中的类、方法

1.创建

 

type S1 struct {
	Name string //成员
	Age  int //成员
     Interfaceer //interface
     Structer // struct }

  

2.声明

var s S1
var s *S1
s := new(S1)

  

3.初始化

s = S1{Name: "go", Age: 2} // 或者 S1{"go", 2}
s = &S1{Name: "go", Age: 2}

  

4.方法:

go语言中的oop很另类,类在go里面叫做receiver,receiver可以是除了interface之外的任何类型。方法和类并非组织在一起,传统的oop方法和类放在一个文件里面,而go语言只要在同一个包里就可,可分散在不同文件里。go的理念就是数据和实现分离.

定义:

func (recv receiver_type) methodName(parameter_list) (return_value_list) { … }
func (_ receiver_type) methodName(parameter_list) (return_value_list) { … }
func (this receiver_type) methodName(parameter_list) (return_value_list) { … }
func (self receiver_type) methodName(parameter_list) (return_value_list) { … }

  

reciever最好定义成指针的形式,因为方法中可能对成员有更改操作.


示例代码:

type S1 struct {
	Name string
	Age  int
}

func (s1 *S1) ChangeName(name string) {
	s1.Name = name
}

func main() {
	s := &S1{Name: "go", Age: 2}
	s.ChangeName("golang")
	fmt.Println(s.Name)
}

  

5.相当另类的构造方法:

type S1 struct {
	Name string
	Age  int
}

// 实现了一个构造方法
func NewS1(n string, a int) *S1 {
	return &S1{n, a}
}

func main() {
	s := NewS1("go", 1)
	fmt.Println(s.Name)
}

  

6.匿名域(类似继承)

type Info struct {
	From   string
	ResNum int
}

type S1 struct {
	Name string
	Age  int
	Info //这是一个匿名域
}

func main() {
	s := new(S1)
	s.From = "google" // From在struct唯一,所以可以直接访问
	s.ResNum = 1000	  // ResNum在struct唯一,所以可以直接访问
	fmt.Println(s)
}

  

二.接口

Go语言中的接口是一些方法的集合(method set),它指定了对象的行为:如果它(任何数据类型)可以做这些事情,那么它就可以在这里使用.
Go语言中一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口.

1.定义

type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
}

  

2.接口赋值
(1).通过struct实例赋值
要求对象实现了接口的所有方法

type Selecter interface {
	Read() int
}

type File struct {
	file string
}

func (f *File) Read() int {
	return len(f.file)
}

func main() {
	file := File{file: "a.txt"} // 创建一个File实例
	selecter := file // 将实例赋值给接口
	fmt.Println(selecter.Read())
}

  

也可以这样:

file := new(File)
file.file = "a.txt"
selecter := file // 将一个指针赋值给接口
fmt.Println(selecter.Read())

// 也可以这样
file := Selecter(File)

  

(2).将接口赋值给另一个接口
假设接口A中定义的所有方法,都在接口B中有定义,那么B接口的实例可以赋值给A的对象。反之不成立.也就是B要包含A,就可以将B接口实例赋值给A

type Selecter interface {
	Read() int
}

type Selecter2 interface {
	Read() int
	Write() int
}

type File struct {
	file string
}

func (f *File) Read() int {
	return len(f.file)
}

func (f *File) Write() int {
	return len(f.file)
}

func main() {
	var selecter2 Selecter2 = &File{file: "a.txt"}
	var selecter Selecter = selecter2 //Selecter中的方法都在Selecter2中,所以可以将Selecter2的实例赋值给Selecter
	fmt.Println(selecter.Read())
}

  

3.接口嵌套

type Selecter2 interface {
	Selecter
	Write() int
}

//等同于:
type Selecter2 interface {
	Read() int
	Write() int
}

4.空接口
空接口比较特殊,它不包含任何方法
在Go语言中,所有其它数据类型都实现了空接口。

t := []int{1, 2, 3, 4}
	s := make([]interface{}, len(t)) //int也实现了空接口,所以可以用interface{}来代替
	for i, v := range t {
		s[i] = v
	}
	fmt.Println(s)

  

5.接口查询
检查对象是否实现了某个接口

type Reader interface {
	Read() int
}

type Writer interface {
	Write() int
}

type File struct {
	filename string
}

func (f *File) Read() int {
	return len(f.filename)
}

func main() {
	var reader Reader = new(File)
	if v, ok := reader.(Writer); ok { // 检查是否实现了Writer接口
		fmt.Println(v, "reader 实现了Writer接口")
	}
}

  

6.类型查询:
在Go语言中,我们可以使用type switch语句查询接口指向的对象实例的类型.一般是和接口查询配合使用.

import (
	"fmt"
)

type Reader interface {
	Read() int
}

type File struct {
	filename string
}

func (f File) Read() int {
	return len(f.filename)
}

func main() {
	var reader Reader = File{filename: "a.txt"}
	switch v := reader.(type) {  // reader必须是一个接口类型
	case File: // v类型是File
		fmt.Println("File", v)
	}
}

  

关于golang的结构体与接口:
结构体定义了属性,接口定义了方法.两者松耦合.举个例子:会英语要会读会写(要实现Read和Write两个方法的接口),如果一个学生(struct,包含学号,姓名等),实现了会读会写,那么就可以说这个学生会英语.如果一个老师(struct,包含学号,姓名等),实现了会读会写,我们就说这个老师会英语.

Duck Type:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
我们并不关心对象是什么类型,到底是不是鸭子,只关心行为.

 

7.类型断言
接口类型向普通类型的转换称为类型断言(运行期确定);
value, b := interface.(Type),value 是 Type 的默认实例;b 是 bool 类型,表明断言是否成立

func main() {
	var arr []int
	if b, ok := interface{}(arr).(int); ok { // arr赋值给空接口,判断是否是int类型
		fmt.Println(b)
	} else {
		fmt.Println("not int array")
	}
}

  

三.关于继承

1.属性继承

type Father struct {
	Name string
}

type Son struct {
	Father
	age int
}

func main() {
	son := Son{Father{"son"}, 10} // 初始化Father
	fmt.Println(son.Father.Name)
}

  

2.方法继承(这个举例不是很妥当)

type Say interface {
	SayName()
	SayAag()
}

type Son struct {
	name string
	Say
}

func (this *Son) SayName() {
	fmt.Println(this.name)
}

func main() {
	son := new(Son)
	son.name = "Son"
	son.SayName()
}

  

3.多重继承

// Father
type Father struct { 
	Book string
}

func (this *Father) Say() {
	fmt.Println("hello world")
}

func (this *Father) Read() {
	fmt.Println(this.Book)
}

// Monther
type Monther struct {
	Age int
}

func (this *Monther) Say() {
	fmt.Println("hello world")
}

// 继承Father和Monther, 并添加一个属性
type Son struct {
	xuehao int
	Father
	Monther
}

func main() {
	son := new(Son)
	son.xuehao = 150
	son.Book = "<rolling>"
	son.Age = 15
	son.Read()
	//son.Say() // 出错,因为Father和Monther都有Say方法,产生混淆
	son.Father.Say()
}