go学习笔记接口部分

接口

接口定义方法

接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。
例子:

type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}
练习 11.1 simple_interface.go:

定义一个接口 Simpler,它有一个 Get() 方法和一个 Set(),Get() 返回一个整型值,Set() 有一个整型参数。创建一个结构体类型 Simple 实现这个接口。

接着定一个函数,它有一个 Simpler 类型的参数,调用参数的 Get() 和 Set() 方法。在 main 函数里调用这个函数,看看它是否可以正确运行。

package main

import (
	"fmt"
)

type Simpler interface {
	get() int
	set(i int) Simpler
}

func show(a Simpler) {
	fmt.Print(a.get(), "\n")
	a = a.set(10)
	fmt.Print(a.get(), "\n")

}

type ss struct {
	i int
}

func (s ss) get() int {
	return s.i
}
func (s ss) set(i int) Simpler {
	s.i = i
	return s
}
func main() {
	var si Simpler
	si = ss{1}
	show(si)
}

练习 11.2 interfaces_poly2.go:

a) 扩展 interfaces_poly.go 中的例子,添加一个 Circle 类型

b) 使用一个抽象类型 Shape(没有字段) 实现同样的功能,它实现接口 Shaper,然后在其他类型里内嵌此类型。扩展 10.6.5 中的例子来说明覆写。

package main

import "fmt"

type shaper interface {
	say(string2 string)
}
type shape struct {
}

func (a *shape) say(string2 string) {
	fmt.Print("i am ", string2)
}

type circle struct {
	name string
	shape
}

func main() {
	c := circle{"circle", shape{}}
	c.say(c.name)
}

在这里插入图片描述

接口嵌套接口

一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。

比如接口 File 包含了 ReadWrite 和 Lock 的所有方法,它还额外有一个 Close() 方法。

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}
如何判断接口类型
方法一varI.(T)

一个接口类型的变量 varI 中可以包含任何类型的值,必须有一种方式来检测它的 动态 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 类型断言 来测试在某个时刻 varI 是否包含类型 T 的值:

v := varI.(T)      

可以多使用下面的代码进行判断,如果转换合法,v 是 varI 转换到类型 T 的值,ok 会是 true;否则 v 是类型 T 的零值,ok 是 false,也没有运行时错误发生。

if v, ok := varI.(T); ok {  // checked type assertion
    Process(v)
    return
}
方法二type-switch

接口变量的类型也可以使用一种特殊形式的 switch 来检测:type-switch
例子:

switch t := areaIntf.(type) {
case *Square:
	fmt.Printf("Type Square %T with value %v\n", t, t)
case *Circle:
	fmt.Printf("Type Circle %T with value %v\n", t, t)
case nil:
	fmt.Printf("nil value: nothing to check?\n")
default:
	fmt.Printf("Unexpected type %T\n", t)
}
练习 11.4 simple_interface2.go:

接着练习 11.1 中的内容,创建第二个类型 RSimple,它也实现了接口 Simpler,写一个函数 fi(),使它可以区分 Simple 和 RSimple 类型的变量。

package main

import (
	"fmt"
)

type Simpler interface {
	get() int
	set(i int)
}
type Rsimple struct {
	i int
}

func (s Rsimple) get() int {
	return s.i
}
func (s Rsimple) set(i int) {
	s.i = i
}

type Simple struct {
	i int
}

func (s Simple) get() int {
	return s.i
}
func (s Simple) set(i int) {
	s.i = i
}
func panduan(items interface{}) {
	switch items.(type) {
	case Simple:
		fmt.Print("it is Simple \n")
	case Rsimple:
		fmt.Print("it is Rsimple\n")
	default:
		fmt.Print("nothing\n")
	}
}
func main() {
	var ss Simpler
	s := Simple{1}
	s1 := Rsimple{2}
	ss = s
	panduan(ss)
	ss = s1
	panduan(ss)

}

在这里插入图片描述

测试一个值是否实现了某个接口

假定 v 是一个值,然后我们想测试它是否实现了 Stringer 接口,可以这样做:

func main() {
	var ss Simpler
	s := Simple{1}
	s1 := Rsimple{2}
	ss = s
	panduan(ss)
	ss = s1
	panduan(ss)
	if sv, ok := interface{}(s1).(Simpler); ok {
		fmt.Printf("v implements Get(): %d\n", sv.get())
	}
}

如果v得类型不是接口那么我们需要使用interface{}先将他转换为接口

接口方法设计的注意事项和规范

在接口上调用方法时,必须有和方法定义时相同的接收者类型或者是可以根据具体类型 P 直接辨识的:

指针方法可以通过指针调用
值方法可以通过值调用
接收者是值的方法可以通过指针调用,因为指针会首先被解引用
接收者是指针的方法不可以通过值调用,因为存储在接口中的值没有地址
将一个值赋值给一个接口时,编译器会确保所有可能的接口方法都可以在此值上被调用,因此不正确的赋值在编译期就会失败。

译注

Go 语言规范定义了接口方法集的调用规则:

类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
类型 T 的可调用方法集包含接受者为 T 的所有方法
类型 T 的可调用方法集不包含接受者为 *T 的方法
上述例子改成指针调用的例子:

package main

import (
	"fmt"
)

type Simpler interface {
	get() int
	set(i int)
}
type Rsimple struct {
	i int
}

func (s *Rsimple) get() int {
	return s.i
}
func (s *Rsimple) set(i int) {
	s.i = i
}

type Simple struct {
	i int
}

func (s *Simple) get() int {
	return s.i
}
func (s *Simple) set(i int) {
	s.i = i
}
func panduan(items interface{}) {
	switch items.(type) {
	case *Simple:
		fmt.Print("it is Simple \n")
	case *Rsimple:
		fmt.Print("it is Rsimple\n")
	default:
		fmt.Print("nothing\n")
	}
}
func main() {
	var ss Simpler
	s := new(Simple)
	s.i = 1
	s1 := new(Rsimple)
	s1.i = 2
	ss = s
	panduan(ss)
	ss = s1
	panduan(ss)
}
练习 11.5 interfaces_ext.go:

a). 继续扩展程序,定义类型 Triangle,让它实现 AreaInterface 接口。通过计算一个特定三角形的面积来进行测试(三角形面积=0.5 * (底 * 高))

b). 定义一个新接口 PeriInterface,它有一个 Perimeter 方法。让 Square 实现这个接口,并通过一个 Square 示例来测试它。

package main

import "fmt"

type AreaInterface interface {
	calArea() float64
}
type PeriInterface interface {
	calPeri() float64
}
type Triangle struct {
	high  int
	width int
}

func (a *Triangle) calArea() float64 {
	res := float64(a.high*a.width) / 2
	return res
}
func (a *Triangle) calPeri() float64 {
	res := float64(a.high+a.width) * 2
	return res
}

type Square struct {
	high  int
	width int
}

func (a *Square) calArea() float64 {
	res := float64(a.high * a.width)
	return res
}
func (a *Square) calPeri() float64 {
	res := float64(a.high+a.width) * 2
	return res
}
func main() {
	var a AreaInterface
	var b PeriInterface
	t1 := Triangle{5, 10}
	t2 := Square{5, 10}
	a = &t1
	fmt.Print(a.calArea(), "\n")
	a = &t2
	fmt.Print(a.calArea(), "\n")
	b = &t1
	fmt.Print(b.calPeri(), "\n")
	b = &t2
	fmt.Print(b.calPeri(), "\n")

}

在这里插入图片描述

练习 11.6 point_interfaces.go:

继续 10.3 中的练习 point_methods.go,定义接口 Magnitude,它有一个方法 Abs()。让 Point、Point3 及 Polar 实现此接口。通过接口类型变量使用方法做 point.go 中同样的事情。

package main

import (
	"fmt"
	"math"
)

type Magnitude interface {
	Abs() float64
	Scale(flag float64)
}
type Point3d struct {
	x int
	y int
	z int
}

func (p *Point3d) Abs() float64 {
	res := math.Sqrt(float64(p.x*p.x + p.y*p.y + p.z*p.z))
	return res
}
func (p *Point3d) Scale(flag float64) {
	lens := p.Abs()
	len_S := lens * flag
	cosx := float64(p.x) / lens
	cosy := float64(p.y) / lens
	cosz := float64(p.z) / lens
	p.x = int(len_S * cosx)
	p.y = int(len_S * cosy)
	p.z = int(len_S * cosz)

}

type Point2d struct {
	x int
	y int
}

func (p *Point2d) Abs() float64 {
	res := math.Sqrt(float64(p.x*p.x + p.y*p.y))
	return res
}
func (p *Point2d) Scale(flag float64) {
	lens := p.Abs()
	len_S := lens * flag
	cosx := float64(p.x) / lens
	cosy := float64(p.y) / lens
	p.x = int(len_S * cosx)
	p.y = int(len_S * cosy)
}

type Polar struct {
	l   float64
	cos float64
}

func (p *Polar) Abs() float64 {
	return p.l
}
func (p *Polar) Scale(flag float64) {
	p.l *= flag
}
func main() {
	var m Magnitude
	p2 := new(Point2d)
	p2.x, p2.y = 5, 5
	p3 := new(Point3d)
	p3.x, p3.y, p3.z = 5, 5, 5
	p := new(Polar)
	p.l, p.cos = 5, 0.6
	m = p2
	res := m.Abs()
	fmt.Print(res, "\n")
	m.Scale(2)
	res = m.Abs()
	fmt.Print(res, "\n")
	m = p3
	res = m.Abs()
	fmt.Print(res, "\n")
	m.Scale(2)
	res = m.Abs()
	fmt.Print(res, "\n")
	m = p
	res = m.Abs()
	fmt.Print(res, "\n")
	m.Scale(2)
	res = m.Abs()
	fmt.Print(res, "\n")
}

在这里插入图片描述

练习 11.7 float_sort.go / float_sortmain.go:

类似 11.7 和示例 11.3/4,定义一个包 float64,并在包里定义类型 Float64Array,然后让它实现 Sorter 接口用来对 float64 数组进行排序。

另外提供如下方法:0

NewFloat64Array():创建一个包含 25 个元素的数组变量(参考 10.2 )
List():返回数组格式化后的字符串,并在 String() 方法中调用它,这样就不用显式地调用 List() 来打印数组(参考 10.7)
Fill():创建一个包含 10 个随机浮点数的数组(参考 4.5.2.6)
在主程序中新建一个此类型的变量,然后对它排序并进行测试。
FloatArray.go

package float64

import (
	"math/rand"
	"strconv"
	"strings"
)

type Float64Array struct {
	res []float64
}

func (f *Float64Array) NewFloat64Array() {
	f.res = make([]float64, 25)
}
func (f *Float64Array) List() string {
	sb := strings.Builder{}
	for _, v := range f.res {
		sb.WriteString(strconv.FormatFloat(v, 'f', 10, 64) + "\t")
	}
	return sb.String()
}
func (f *Float64Array) String() string {
	return f.List()
}
func (f *Float64Array) Fill() {
	f.res = make([]float64, 10)
	for i, _ := range f.res {
		f.res[i] = rand.Float64()
	}
}
func (f Float64Array) Len() int {
	return len(f.res)
}
func (f Float64Array) Less(i, j int) bool {
	if f.res[i] > f.res[j] {
		return true
	} else {
		return false
	}
}
func (f Float64Array) Swap(i, j int) {
	temp := f.res[i]
	f.res[i] = f.res[j]
	f.res[j] = temp
}

main.go

package main

import (
	float642 "awesomeProject/float64"
	"fmt"
	"sort"
)

func main() {
	var ff float642.Float64Array
	ff.Fill()
	fmt.Printf("%v\n", ff)
	var ff1 float642.Float64Array
	ff1.NewFloat64Array()
	fmt.Printf("%v\n", ff1)
	sort.Sort(ff)
	fmt.Printf("%v\n", ff)

}

结果:
在这里插入图片描述

练习 11.8 sort.go / sort_persons.go:

定义一个结构体 Person,它有两个字段:firstName 和 lastName,为 []Person 定义类型 Persons 。让 Persons 实现 Sorter 接口并进行测试。

package main

import (
	"fmt"
	"sort"
	"strings"
)

type Person struct {
	firstName string
	lastName  string
}
type Persons []Person

func (p Persons) String() string {
	sb := strings.Builder{}
	for i, _ := range p {
		sb.WriteString(p[i].firstName + " " + p[i].lastName + "\t")
	}
	return sb.String()
}
func (p Persons) Len() int {
	return len(p)
}
func (p Persons) Less(i, j int) bool {
	pi, pj := p[i], p[j]
	if strings.Compare(pi.firstName, pj.firstName) == 1 {
		return true
	} else if strings.Compare(pi.firstName, pj.firstName) == -1 {
		return false
	} else {
		if strings.Compare(pi.lastName, pj.lastName) == 1 {
			return true
		} else if strings.Compare(pi.lastName, pj.lastName) == -1 {
			return false
		} else {
			return false
		}
	}
}
func (p Persons) Swap(i, j int) {
	temp := p[i]
	p[i] = p[j]
	p[j] = temp
}
func main() {
	ps := Persons{Person{"asda", "ada"}, Person{"dasda", "adasdsa"}, Person{"dasdas", "dadasgdg"}, Person{"asda", "fdghfdghd"}}
	fmt.Printf("%v\n", ps)
	sort.Sort(ps)
	fmt.Printf("%v\n", ps)

}

结果:
在这里插入图片描述

空接口

空接口或者最小接口 不包含任何方法,它对实现不做任何要求:

type Any interface {}
练习 11.9 simple_interface3.go:

继续练习 11.2,在它中添加一个 gI() 函数,它不再接受 Simpler 类型的参数,而是接受一个空接口参数。然后通过类型断言判断参数是否是 Simpler 类型。最后在 main 使用 gI() 取代 fI() 函数并调用它。确保你的代码足够安全。

package main

import (
	"fmt"
)

type any interface {
}

func gl(a any) {
	if v, ok := a.(Simpler); ok {
		show(v)
	}
}

type Simpler interface {
	get() int
	set(i int) Simpler
}

func show(a Simpler) {
	fmt.Print(a.get(), "\n")
	a = a.set(10)
	fmt.Print(a.get(), "\n")

}

type ss struct {
	i int
}

func (s ss) get() int {
	return s.i
}
func (s ss) set(i int) Simpler {
	s.i = i
	return s
}
func main() {
	var si Simpler
	si = ss{1}
	var a any
	a = si
	gl(a)
}
用空接口构建通用类型或包含不同类型变量的数组

们给空接口定一个别名类型 Element:type Element interface{}

然后定义一个容器类型的结构体 Vector,它包含一个 Element 类型元素的切片:

type Vector struct {
	a []Element
}

Vector 里能放任何类型的变量,因为任何类型都实现了空接口,实际上 Vector 里放的每个元素可以是不同类型的变量。我们为它定义一个 At() 方法用于返回第 i 个元素:

func (p *Vector) At(i int) Element {
	return p.a[i]
}
再定一个 Set() 方法用于设置第 i 个元素的值:

func (p *Vector) Set(i int, e Element) {
	p.a[i] = e
}

Vector 中存储的所有元素都是 Element 类型,要得到它们的原始类型(unboxing:拆箱)需要用到类型断言。TODO:The compiler rejects assertions guaranteed to fail,类型断言总是在运行时才执行,因此它会产生运行时错误。

练习 11.10 min_interface.go / minmain.go:

仿照 11.7 中开发的 Sorter 接口,创建一个 Miner 接口并实现一些必要的操作。函数 Min() 接受一个 Miner 类型变量的集合,然后计算并返回集合中最小的元素。

package main

import (
	"fmt"
	"strings"
)

type Element interface {
}
type Miner interface {
	Len() int
	Swap(i, j int)
	Less(i, j int) bool
	At(i int) Element
	Set(i int, e Element)
}
type Vector struct {
	a []Element
}

func (p *Vector) Len() int {
	return len(p.a)
}

// 不同类型sting>float64>float32>int
func (p *Vector) Less(i, j int) bool {
	pi, pj := p.a[i], p.a[j]
	switch pi.(type) {
	case int:
		switch pj.(type) {
		case int:
			piv, pjv := pi.(int), pj.(int)
			if piv > pjv {
				return true
			} else {
				return false
			}
		case float32:
			return false
		case float64:
			return false
		case string:
			return false
		}
	case string:
		switch pj.(type) {
		case string:
			piv, pjv := pi.(string), pj.(string)
			if strings.Compare(piv, pjv) == 1 {
				return true
			} else {
				return false
			}
		case int:
			return true
		case float64:
			return true
		case float32:
			return true
		}
	case float64:
		switch pj.(type) {
		case float64:
			piv, pjv := pi.(float64), pj.(float64)
			if piv > pjv {
				return true
			} else {
				return false
			}
		case string:
			return false
		case int:
			return true
		case float32:
			return true
		}
	case float32:
		switch pj.(type) {
		case float32:
			piv, pjv := pi.(float32), pj.(float32)
			if piv > pjv {
				return true
			} else {
				return false
			}
		case string:
			return false
		case int:
			return true
		case float64:
			return false
		}
	}
	return false
}
func (p *Vector) Swap(i, j int) {
	pi, pj := p.a[i], p.a[j]
	p.Set(i, pj)
	p.Set(j, pi)
}
func (p *Vector) At(i int) Element {
	return p.a[i]
}
func (p *Vector) Set(i int, e Element) {
	p.a[i] = e
}
func Sort(data Miner) {
	for pass := 1; pass < data.Len(); pass++ {
		for i := 0; i < data.Len()-pass; i++ {
			if data.Less(i+1, i) {
				data.Swap(i, i+1)
			}
		}
	}
}
func Min(data Miner) Element {
	Sort(data)
	lens := data.Len()
	return data.At(lens - 1)
}
func Max(data Miner) Element {
	Sort(data)
	return data.At(0)
}
func main() {

	v := Vector{[]Element{123, 464, 13.01, 15430.154, "adsdsa", "adadasda", "tyurueueue"}}
	res := Min(&v)
	switch res.(type) {
	case int:
		fmt.Print(res.(int))
	case string:
		fmt.Print(res.(string))
	case float64:
		fmt.Print(res.(float64))
	case float32:
		fmt.Print(res.(float32))
	}
	res1 := Max(&v)
	switch res1.(type) {
	case int:
		fmt.Print(res1.(int))
	case string:
		fmt.Print(res1.(string))
	case float64:
		fmt.Print(res1.(float64))
	case float32:
		fmt.Print(res1.(float32))
	}
}

结果:
在这里插入图片描述

反射

两个简单的函数,reflect.TypeOf 和 reflect.ValueOf,返回被检查对象的类型和值。他们的返回值分别为reflect.Type 和 reflect.Value类型。有许多方法用于检查和操作它们。 Type 和 Value 都有 Kind() 方法返回一个常量来表示类型:Uint、Float64、Slice 等等。同样 Value 有叫做 Int() 和 Float() 的方法可以获取存储在内部的值(跟 int64 和 float64 一样)Kind() 总是返回底层类型:
例子:

func main() {
	type MyInt int
	var m MyInt = 5
	v := reflect.ValueOf(m)
	fmt.Println(v.Kind())
	fmt.Println(v.Type())
	fmt.Println(v.Int())

}

结果:
在这里插入图片描述

通过反射修改(设置)值

假设我们要把 x 的值改为 3.1415。Value 有一些方法可以完成这个任务。首先需要判断是否可设置,是否可设置是 Value 的一个属性,并且不是所有的反射值都有这个属性:可以使用 CanSet() 方法测试是否可设置。当 v := reflect.ValueOf(x) 函数通过传递一个 x 拷贝创建了 v,那么 v 的改变并不能更改原始的 x。要想 v 的更改能作用到 x,那就必须传递 x 的地址 v = reflect.ValueOf(&x)。通过 Type() 我们看到 v 现在的类型是 *float64 并且仍然是不可设置的。要想让其可设置我们需要使用 Elem() 函数,这间接地使用指针:v = v.Elem()现在 v.CanSet() 返回 true 并且v.SetFloat(3.1415) 设置成功了

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var x float64 = 3.4
	v := reflect.ValueOf(x)
	// setting a value:
	// v.SetFloat(3.1415) // Error: will panic: reflect.Value.SetFloat using unaddressable value
	fmt.Println("settability of v:", v.CanSet())
	v = reflect.ValueOf(&x) // Note: take the address of x.
	fmt.Println("type of v:", v.Type())
	fmt.Println("settability of v:", v.CanSet())
	v = v.Elem()
	fmt.Println("The Elem of v is: ", v)
	fmt.Println("settability of v:", v.CanSet())
	v.SetFloat(3.1415) // this works!
	fmt.Println(v.Interface())
	fmt.Println(v)
}

结果:
在这里插入图片描述

反射结构

有些时候需要反射一个结构类型。NumField() 方法返回结构内的字段数量;通过一个 for 循环用索引取得每个字段的值 Field(i)。但是如果尝试更改一个值,需将
被导出字段的首字母大写设置为大写。

package main

import (
	"fmt"
	"reflect"
	"strconv"
)

type test struct {
	s1, s2, s3 string
}
type Test struct {
	S1, S2, S3 string
}
type any interface {
}

func main() {
	var any1 any
	any1 = test{"adas", "adasd", "dasdad"}
	any3 := Test{"huw", "adhjs", "wequwe"}
	value := reflect.ValueOf(any1)
	value1 := reflect.ValueOf(&any3).Elem()

	for i := 0; i < value.NumField(); i++ {
		fmt.Printf("Field %d: %v\n", i, value.Field(i))
		fmt.Printf("Field %d: %v\n", i, value1.Field(i).Interface())
		value1.Field(i).SetString(strconv.Itoa(i))
	}
	for i := 0; i < value.NumField(); i++ {
		fmt.Printf("Field %d: %v\n", i, value1.Field(i))
	}
}

在这里插入图片描述

练习 11.11:map_function_interface.go:

在练习 7.13 中我们定义了一个 map() 函数来使用 int 切片 (map_function.go)。

通过空接口和类型断言,现在我们可以写一个可以应用于许多类型的泛型的 map() 函数,为 int 和 string 构建一个把 int 值加倍和将字符串值与其自身连接(译者注:即 “abc” 变成 “abcabc” )的 map() 函数 mapFunc()。

提示:为了可读性可以定义一个 interface{} 的别名,比如:type obj interface{}。

package main

import "fmt"

type any interface{}

func main() {
	// define a generic lambda function mf:
	mf := func(i any) any {
		switch i.(type) {
		case int:
			return i.(int) * i.(int)
		case string:
			return i.(string) + i.(string)
		}
		return i
	}

	isl := []any{0, 1, 2, 3, 4, 5}
	res1 := mapFunc(mf, isl)
	for _, v := range res1 {
		fmt.Println(v)
	}
	println()

	ssl := []any{"0", "1", "2", "3", "4", "5"}
	res2 := mapFunc(mf, ssl)
	for _, v := range res2 {
		fmt.Println(v)
	}
}

func mapFunc(mf func(any) any, list []any) []any {
	result := make([]any, len(list))
	for ix, v := range list {
		result[ix] = mf(v)
	}
	return result
}

在这里插入图片描述

练习 11.12:map_function_interface_var.go:

稍微改变练习 11.11,允许 mapFunc() 接收不定数量的 items。

package main

import "fmt"

type any interface{}

func main() {
	// define a generic lambda function mf:
	mf := func(i any) any {
		switch i.(type) {
		case int:
			return i.(int) * i.(int)
		case string:
			return i.(string) + i.(string)
		}
		return i
	}

	res1 := mapFunc(mf, 1, 2, 3, 4, 5, 6, 7)
	for _, v := range res1 {
		fmt.Println(v)
	}
	println()

	res2 := mapFunc(mf, "1", "2", "3", "4", "5", "6")
	for _, v := range res2 {
		fmt.Println(v)
	}
}

func mapFunc(mf func(any) any, list ...any) []any {
	result := make([]any, len(list))
	for ix, v := range list {
		result[ix] = mf(v)
	}
	return result
}

在这里插入图片描述

练习 11.13:main_stack.go—stack/stack_general.go:

在练习 10.16 和 10.17 中我们开发了一些栈结构类型。但是它们被限制为某种固定的内建类型。现在用一个元素类型是 interface{}(空接口)的切片开发一个通用的栈类型。

实现下面的栈方法:

Len() int
IsEmpty() bool
Push(x interface{})
Pop() (interface{}, error)
Pop() 改变栈并返回最顶部的元素;Top() 只返回最顶部元素。

在主程序中构建一个充满不同类型元素的栈,然后弹出并打印所有元素的值。

package main

import "fmt"

type any interface{}
type tank struct {
	val []any
	len int
}

func (this *tank) Len() int {
	return this.len
}
func (this *tank) IsEmpty() bool {
	if this.len == 0 {
		return true
	} else {
	}
}
func (this *tank) Push(x any) {
	this.val = append(this.val, x)
	this.len++
}
func (this *tank) Pop() any {
	res := this.val[this.len-1]
	this.len--
	return res

}
func main() {
	var t tank
	fmt.Println(t.IsEmpty())
	fmt.Println(t.Len())
	t.Push("asdasd")
	t.Push(1)
	t.Push(1.4546)
	t.Push(rune('a'))
	fmt.Println(t.IsEmpty())
	fmt.Println(t.Len())
	for i := 0; i < len(t.val); i++ {
		fmt.Println(t.Pop())
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值