Go基础系列:接口类型探测和type-switch

接口类型探测:类型断言

接口实例中存储了实现接口的类型实例,类型的实例有两种:值类型实例和指针类型实例。在程序运行过程中,接口实例存储的实例类型可能会动态改变。例如:

// ins是接口实例
var ins Shaper

// ins存储值类型的实例
ins = c1

// 一段时间后...
...

// ins存储指针类型的实例,存储的类型发生改变
ins = c2

// 一段时间后...

// ins可能存储另一个类型实例
ins = s1

所以,需要一种探测接口实例所存储的是值类型还是指针类型。

探测的方法是:ins.(Type)ins.(*Type)。它们有两个返回值,第二个返回值是ok返回值,布尔类型,第一个返回值是探测出的类型。也可以只有一个返回值:探测出的类型。

// 如果ins保存的是值类型的Type,则输出
if t, ok := ins.(Type); ok {
    fmt.Printf("%T\n", v)
}

// 如果ins保存的是指针类型的*Type,则输出
if t, ok := ins.(*Type); ok {
    fmt.Printf("%T\n", v)
}

// 一个返回值的探测
t := ins.(Type)
t := ins.(*Type)

以下是一个例子:

package main

import "fmt"

// Shaper 接口类型
type Shaper interface {
    Area() float64
}

// Square struct类型
type Square struct {
    length float64
}

// Square类型实现Shaper中的方法Area()
func (s Square) Area() float64 {
    return s.length * s.length
}

func main() {
    var ins1, ins2, Shaper

    // 指针类型的实例
    s1 := new(Square)
    s1.length = 3.0
    ins1 = s1
    if v, ok := ins1.(*Square); ok {
        fmt.Printf("ins1: %T\n", v)
    }

    // 值类型的实例
    s2 := Square{4.0}
    ins2 = s2
    if v, ok := ins2.(Square); ok {
        fmt.Printf("ins2: %T\n", v)
    }
}

上面两个Printf都会输出,因为它们的类型判断都返回true。如果将ins2.(Square)改为ins2.(*Square),第二个Printf将不会输出,因为ins2它保存的是值类型的实例。

特别需要注意的是,ins必须明确是接口实例。例如,以下前两种声明是有效的,第三种推断类型是错误的,因为它可能是接口实例,也可能是类型的实例副本。

var ins Shaper     // 正确
ins := Shaper(s1)  // 正确
ins := s1          // 错误

当ins不能确定是接口实例时,用它来进行测试,例如ins.(Square)将会报错:

invalid type assertion:ins.(Square) (non-interface type (type of ins) on left)

它说明了左边的ins是非接口类型(non-interface type)。

type Switch结构

switch流程控制结构还可以用来探测接口实例保存的类型。这种结构称为type-switch

用法如下:

switch v := ins.(type) {
case *Square:
    fmt.Printf("Type Square %T\n", v)
case *Circle:
    fmt.Printf("Type Circle %T\n", v)
case nil:
    fmt.Println("nil value: nothing to check?")
default:
    fmt.Printf("Unexpected type %T", v)
}

其中ins.(type)中的小写type是固定的词语。

以下是一个使用示例:

package main

import (
    "fmt"
)

// Shaper 接口类型
type Shaper interface {
    Area() float64
}

// Circle struct类型
type Circle struct {
    radius float64
}

// Circle类型实现Shaper中的方法Area()
func (c *Circle) Area() float64 {
    return 3.14 * c.radius * c.radius
}

// Square struct类型
type Square struct {
    length float64
}

// Square类型实现Shaper中的方法Area()
func (s Square) Area() float64 {
    return s.length * s.length
}

func main() {
    s1 := &Square{3.3}
    whichType(s1)

    s2 := Square{3.4}
    whichType(s2)

    c1 := new(Circle)
    c1.radius = 2.3
    whichType(c1)
}

func whichType(n Shaper) {
    switch v := n.(type) {
    case *Square:
        fmt.Printf("Type Square %T\n", v)
    case Square:
        fmt.Printf("Type Square %T\n", v)
    case *Circle:
        fmt.Printf("Type Circle %T\n", v)
    case nil:
        fmt.Println("nil value: nothing to check?")
    default:
        fmt.Printf("Unexpected type %T", v)
    }
}

上面的type-switch中,之所以没有加上case Circle,是因为Circle只实现了指针类型的receiver,根据Method Set对接口的实现规则,只有指针类型的Circle示例才算是实现了接口Shaper,所以将值类型的示例case Circle放进type-switch是错误的。

原文地址:https://www.cnblogs.com/f-ck-need-u/p/9893347.html

时间: 2024-10-10 03:09:13

Go基础系列:接口类型探测和type-switch的相关文章

C#基础系列-接口

前言: 完全是我在学习过程中记录的笔记,只不过分享一下让很多刚开始学习.net编程的人能够很快的学会C#语言 接口 (1) 有时候需要考虑子类中一部分具有某些能力(方法),同时又需要考虑其多态的特征,这时候可以考虑接口 (2)语法: public interface 接口名 { //成员 } (3) 接口的存在就是为了被实现 (4)有了接口以后实现该接口的子类可以赋值给这个接口的变量,就可以实现多态了 (5)接口的存在就是为了多态 (6)接口与类的其中一个不同点在于多"继承"(实现)

软件测试之接口测试基础知识接口类型、测试工具

HTTP,webservice,socket HTTP:分为get和post类型 Webservice也分get和post类型.(一般wsdl结尾,即webservice接口) Socket:少见. Http接口测试工具: Jmeter Firefox插件httprequester 在线工具http://www.atool.org/httptest.php postman soapui loadrunner 原文地址:https://www.cnblogs.com/hisweety/p/1084

C#基础系列——一场风花雪月的邂逅:接口和抽象类

前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗.博主呵呵一笑,回想当初的自己,不也有此种疑惑么...今天打算针对他的问题,结合一个实际的使用场景来说明下抽象类和接口的异同,到底哪些情况需要用接口?又有哪些情况需要用抽象类呢? C#基础系列目录: C#基础系列——Linq to Xml读写xml C#基础系列——扩展方法的使用 C#基础系列——序

夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接口与抽象类的本质区别是什么? 基本语法区别 设计思想区别 如何回答面试题:接口和抽象类的区别? 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl

Go基础系列:Go接口

接口用法简介 接口(interface)是一种类型,用来定义行为(方法). type Namer interface { my_method1() my_method2(para) my_method3(para) return_type ... } 但这些行为不会在接口上直接实现,而是需要用户自定义的方法来实现.所以,在上面的Namer接口类型中的方法my_methodN都是没有实际方法体的,仅仅只是在接口Namer中存放这些方法的签名(签名 = 函数名+参数(类型)+返回值(类型)). 当用

基础知识系列?接口的显示实现和隐式实现

x CLR via C#中的一个小结将标题定为:"13.5 隐式和显式接口方法实现(幕后发生的事情)"... 直接上代码 public interface I { int GetIntFun(); int GetIntFunVirtual(); string GetStrFun(); } public class 我是一个类名字叫雷雷 : I { /// <summary> /// 隐式实现-派生类不可以重写 /// 0.必须标记为public,否则报错:{"我是

C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是PropertyGrid了,我们仅仅需要使用一个PropertyGrid.SelectedObject = Control就可以搞定,让PropertyGrid显示Control的所有属性.可是这里显示的属性名是英文的.对于我们开发人员来说这无可厚非,我们也乐于接受.并且让PropertyGrid显示中文属性名,这对于我们开发人员的使用来说显得多此一举.可是,对于我这种类型的一个应用工具,英文属性名对于很多客户来说可能就很难懂

Spring基础系列12 -- Spring AOP AspectJ

Spring基础系列12 -- Spring AOP AspectJ 转载:http://www.cnblogs.com/leiOOlei/p/3613352.html 本文讲述使用AspectJ框架实现Spring AOP. 再重复一下Spring AOP中的三个概念, Advice:向程序内部注入的代码. Pointcut:注入Advice的位置,切入点,一般为某方法. Advisor:Advice和Pointcut的结合单元,以便将Advice和Pointcut分开实现灵活配置. Aspe

C#基础系列——Attribute特性使用

前言:上篇 C#基础系列--反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术--特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属性.方法等具有某些统一的特征,从而达到某些特殊的需要.比如:方法的异常捕捉,你是否还在某些可能出现异常的地方(例如数据库的操作.文件的操作等)经常使用try...catch.这个时候如果使用特性,就可以大大减少方法里面的try...catch的使用.你只需要定义一个专门捕捉异常的特性类Excepti