类型断言:

语法:
<目标类型的值>,<布尔参数> := <表达式>.( 目标类型 ) // 安全类型断言
<目标类型的值> := <表达式>.( 目标类型 )  //非安全类型断言

x.(T),这里x表示一个接口的类型,T表示一个类型(也可为接口类型)。
一个类型断言检查一个接口对象x的动态类型是否和断言的类型T匹配。

类型断言分两种情况:
第一种,如果断言的类型T是一个具体类型,类型断言x.(T)就检查x的动态类型是否和T的类型相同。

如果这个检查成功了,类型断言的结果是一个类型为T的对象,该对象的值为接口变量x的动态值。换句话说,具体类型的类型断言从它的操作对象中获得具体的值。
如果检查失败,接下来这个操作会抛出panic,除非用两个变量来接收检查结果,如:f, ok := w.(*os.File)
第二种,如果断言的类型T是一个接口类型,类型断言x.(T)检查x的动态类型是否满足T接口。

如果这个检查成功,则检查结果的接口值的动态类型和动态值不变,但是该接口值的类型被转换为接口类型T。换句话说,对一个接口类型的类型断言改变了类型的表述方式,改变了可以获取的方法集合(通常更大),但是它保护了接口值内部的动态类型和值的部分。
如果检查失败,接下来这个操作会抛出panic,除非用两个变量来接收检查结果,如:f, ok := w.(io.ReadWriter)
注意:

如果断言的操作对象x是一个nil接口值,那么不论被断言的类型T是什么这个类型断言都会失败。
我们几乎不需要对一个更少限制性的接口类型(更少的方法集合)做断言,因为它表现的就像赋值操作一样,除了对于nil接口值的情况。

面试题:怎么样判断一个变量的类型?

package main

import "fmt"

var container = []string{"zero", "one", "two"}

func main() {
container := map[int]string{: "zero", : "one", : "two"}
fmt.Printf("The element is %q.\n", container[])
}

回答:

使用“类型断言”表达式。
value, ok := interface{}(container).([]string)
在赋值符号的右边,是一个类型断言表达式。
把container变量的值转换为空接口值的interface{}(container)。
以及一个用于判断前者类型是否为切片类型[]string的 .([]string)。

解析:
类型断言表达式的语法形式是x.(T)。其中x代表要被判定类型的值。这个值的类型必须是接口类型的,不过无关哪个接口类型。
所以如果container不是任何的接口类型时,需要先转换成某个接口类型。
如果是,这个断言表达是可以写成container.([]string)。

最右边的圆括号中 []string 是一个类型字面量。类型字面量,就是用来表示数据类型本身的若干个字符。
比如,string是表示字符类型的字面量,uint8是表示8位无符号整数类型的字面量。

一对不包裹任何东西的花括号,既可以代表空代码块,也可以表示不包含任何内容的数据结构(数据类型)。

struct{}表示不包含任何字段和方法的空结构体类型。
[]string{}表示空切片值(数据类型)。
map[int]string{}表示空字典值,类型字面量是表示数据类型本身的若干个字符,如string是字符串类型的字面量,uint8表示8位无符号整数类型的字面量。
其中[]string表示元素类型为string的切片类型;
map[int]string表示键类型为int,值类型为string的字典类型。


类型转换:

语法:<结果类型> := <目标类型> ( <表达式> )
T(x)
T表示类型,x可以是变量,也可以是一个代表值的字面量(比如1.23和struct{})

var a int =
var b := float(a)

类型转换是用来在不同但相互兼容的类型之间的相互转换的方式,所以,当类型不兼容的时候,是无法转换的。

int<--->string

//string到int
value_int,err:=strconv.Atoi(string)
//int到string
str:=strconv.Itoa(value_int)

int64<--->string

//string到int64
value_int64, err := strconv.ParseInt(string, , )
//int64到string,需注意下面转换规定
//FormatInt returns the string representation of i in the given base, for 2 <= base <= 36.
//The result uses the lower-case letters 'a' to 'z' for digit values >= 10
str:=strconv.FormatInt(value_int64, ) //FormatInt第二个参数表示进制,10表示十进制

float<--->string

//float转string
v := 3.1415926535
s1 := strconv.FormatFloat(v, 'E', -, )//float32
s2 := strconv.FormatFloat(v, 'E', -, )//float64
//第二个参数可选'f'/'e'/'E'等,含义如下:
// 'b' (-ddddp±ddd,二进制指数)
// 'e' (-d.dddde±dd,十进制指数)
// 'E' (-d.ddddE±dd,十进制指数)
// 'f' (-ddd.dddd,没有指数)
// 'g' ('e':大指数,'f':其它情况)
// 'G' ('E':大指数,'f':其它情况) //string转float
s := "3.1415926535"
v1, err := strconv.ParseFloat(v, )
v2, err := strconv.ParseFloat(v, )

float<--->int

var a int64
a =
var b float64
b = 2.000 //a -- float64
c := float64(a) //b -- int64
d := int64(b)

思考题:1. 你认为类型转换规则中有哪些值得注意的地方?

1、 对于整数类型值、整数常量之间的类型转换,原则上只要源值在目标类型的可表示范围内就是合法的。
源整数类型的可表示范围较大,而目标类型的可表示范围较小的情况,比如把int16转换为int8,如:

var srcInt = int16(-)
dstInt := int8(srcInt)

其中变量srcInt的值是int16类型的-255转化来的,而变量dstInt的值是srcInt转换来的,类型是int8。

此例子中,int16类型比int8的范围要大,运行结果为:1.
整数在Go中是以补码的形式存储的,补码其实就是原码个位求反再加1.
int16类型的值-255的补码是1111111100000001,如果转换为int8类型,那么Go就会把在较高位置(最左位置)上的8位二进制直接截掉,从而得到00000001.
又由于最左边一位是0,表示它是个正整数,而正整数的补码就等于其原码,所以这里输出1.

2、虽然直接把一个整数值转为一个string类型的值是可行的,但是被转换的整数值必须要能代表一个有效的Unicode代码点。

3、string类型与各种切片类型之间的互转。
一个值从string类型向[]byte类型转换时,代表着以UTF-8编码的字符串会被拆分成独立的字节,两个字节代表一个汉字。
一个值从string类型向[]rune类型转换时,代表着字符串会被拆分成一个个的Unicode字符,一个字符代表一个汉字。

2. 什么是别名类型?什么是潜在类型?

别名类型是type声明自定义类型的一种,如:

type MyString = string

表示MyString是string类型的别名类型,与其源类型是完全相同的。
别名类型主要是为了代码重构而存在的。
byte是uint8的别名类型,rune是int32的别名类型。

潜在类型是某个类型在本质上是哪个类型或者是哪个类型的集合,如:

type MyString2 string

潜在类型的定义之间没有“=”号
潜在类型的值之间是可以进行类型转换的,如本例中MyString2类型的值可以跟string类型的值互相转换,但是集合类的类型[]MyString2与[]string就不行,

因为他们的潜在类型就不同了,分别是MyString2和string。

即使两个类型的潜在类型相同,他们的值之间也不能进行判断或比较,他们的变量之间也不能互相赋值。

3. 别名类型在代码重构过程中可以起到哪些作用吗?

类型别名是 Go 1.9 版本添加的新功能。主要用于代码升级、迁移中类型的兼容性问题。
下一篇分析类型别名和类型定义。

总结
类型断言表达式可用来判断变量是哪个类型,把结果赋给两个变量,要保证被判断的变量是接口类型的,这可能会用到类型转换表达式。
要搞清楚别名类型声明与类型再定义之间的区别。

本学习笔记仅为了总结自己学到的Go语言核心知识,方便以后回忆,文中部分内容摘录自极客时间的《Go语言核心36讲》专栏,如有侵权,请联系我删除。

 

[Golang学习笔记] 06 程序实体3 类型断言和类型转换的更多相关文章

  1. [Golang学习笔记] 05 程序实体2 作用域访问权限和变量重声明

    作用域访问权限: 程序实体访问权限(作用域)有三种:1. 包级私有(代码包)2. 模块级私有(代码包)3. 公开(全域). 一个函数是一个代码块.一个程序实体的作用域总是会被限制在某个代码块中.好处: ...

  2. [Golang学习笔记] 04 程序实体1 变量声明

    变量声明: Go语言的程序实体包含:变量.常量.函数.结构体和接口,是一门静态类型的编程语言. (在声明变量或常量的时候,需要指定类型,或者给予足够信息是的Go语言能够推导出类型) Go语言变量的类型 ...

  3. golang学习笔记8 beego参数配置 打包linux命令

    golang学习笔记8 beego参数配置 打包linux命令 参数配置 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/mvc/contro ...

  4. go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE

    go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE Go语言是谷歌2009发布的专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速 ...

  5. golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题

    golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ...

  6. golang学习笔记16 beego orm 数据库操作

    golang学习笔记16 beego orm 数据库操作 beego ORM 是一个强大的 Go 语言 ORM 框架.她的灵感主要来自 Django ORM 和 SQLAlchemy. 目前该框架仍处 ...

  7. golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换

    golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...

  8. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  9. golang学习笔记5 用bee工具创建项目 bee工具简介

    golang学习笔记5 用bee工具创建项目 bee工具简介 Bee 工具的使用 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/instal ...

随机推荐

  1. Effective C++(9) 构造函数调用virtual函数会发生什么

    问题聚焦: 不要在构造函数和析构函数中调用virtual函数,因为这样的调用不会带来你预想的结果. 让我先来看一下在构造函数里调用一个virtual函数会发生什么结果 Demo class Trans ...

  2. Windows 7 控制面板Update选项灰色解决办法

    具体解决方法是开始-运行-regedit,打开注册表编辑器,在注册表里找: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows,展开Windo ...

  3. 深入浅出SharePoint2010——请假系统无代码篇之权限设计

    首选我们需要区分3个跟权限相关的概念. 权限项目(Permission):最小的权限粒度.比如创建列表项.审批等. 权限级别(Permission Level):权限项目不能直接赋予用户或者用户组,只 ...

  4. PHP版本解密openrtb中的价格

    Decrypt Price Confirmations 原文地址 https://developers.google.com/ad-exchange/rtb/response-guide/decryp ...

  5. ipconfig命令一览

    前文用到了ipconfig /displaydns和ipconfig /flushdns,加上之前经常ipconfig查ip,今天看了一下别的命令,用的不多,仅作备忘~~ 命令行窗口中输入ipconf ...

  6. SVM中为何间隔边界的值为正负1

    在WB二面中,问到让讲一下SVM算法. 我回答的时候,直接答道线性分隔面将样本分为正负两类,取平行于线性切割面的两个面作为间隔边界,分别为:wx+b=1和wx+ b = -1. 面试官就问,为什么是正 ...

  7. BZOJ1821:[JSOI2010]部落划分(并查集,二分)

    Description 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成 ...

  8. 1、Spring Cloud - 微服务简介

    前言: 业界大牛马丁.福勒(Martin Fowler) 这样描述微服务: 论文网址:https://martinfowler.com/articles/microservices.html 就目前而 ...

  9. Redis入门(一)---安装

    一.Ubuntu安装 1.命令行安装 sudo apt-get install redis-server 2.启动redis服务(安装完成后自动启动) sudo /etc/init.d/redis-s ...

  10. [LuoguP1360][USACP07MAR]黄金阵容均衡

    [LuoguP1360][USACP07MAR]黄金阵容均衡(Link) 每天会增加一个数\(A\),将\(A\)二进制分解为\(a[i]\),对于每一个\(i\)都增加\(a[i]\),如果一段时间 ...