Golang中的内置函数

??Go中存在着不少内置函数,此类函数并不需要引入相关Package就可以直接使用该类函数。在Go的源码builtin包的builtin.go中定义Go所有的内置函数;但该文件仅仅是定义描述出了所有内置函数,并不包含函数的任何实现代码,该文件除了定义了内置函数还定义了部分内置类型;

内置函数使用

len(“123”)
println(“log”)
fmt.Println(“fmt”)   // 非内置函数使用,调用fmt包中的函数

常用内置函数

close: 用于发送方关闭chan,仅适用于双向或发送通道。

len、cap: 用于获取数组、Slice、map、string、chan类型数据的长度或数量,len返回长度、cap返回容量;

new、make: new用于值类型、用户定义类型的内存分配,new(T)将分配T类型零值返回其指向T类型的指针;make用于引用类型(Slice、map、chan)内存分配返回初始化的值,不同类型使用有所区别。

make(chan int)  创建无缓冲区的通道
make(chan int,10)  创建缓冲区为10的通道
make([]int,1,5)   创建长度为1,容量为5的slice
make([]int,5) 创建容量长度都为5的slice
make(map[int] int) 创建不指定容量的map
make(map[int] int,2) 创建容量为2的map

copy、apped: 用于复制slice与为slice追加元素;

print、println: 用于打印输出;

panic、recover: 用于错误处理;

delete: 用于删除map中的指定key

内置函数len的实现

??我们在builtin中仅仅只是看到了内置函数的定义描述,并没有函数的具体实现,也没有再其他包中找到具体的实现。那该内置函数到底是怎么实现的呢。

??Golang是一种编译型语言,Go程序在运行前需要先通过编译器生成二进制码才能在目标机器上运行。Go的内置函数处理正是藏身于编译器当中,下面将简单分析len内置函数的具体实现;

??通常的编译器都包含了词法分析、语法分析、类型检查、中间代码生成、机器码生成这几个阶段,Go编译器也不例外;

??不同的计算机架构有着不同的机器码,直接把高级语言生成机器码相对比较困难,对高级语言的优化分析也不容易做,所以需要借助中间代码,Go编译器所生成的中间代码具有静态单赋值特征(Static Single Assigment, SSA),具有该特征的中间代码每个变量只会被赋值一次,通过该特征在中间代码分析时就可以明确发现哪些无效代码,机器码生成时就可减少某些无效指令,进而减少指令的执行。内置函数正是在中间代码阶段进行具体实现的;

len内置函数在编译器实现

??在编译器的cmd\compile\internal\gc\universe.go类中可以看到每个内置函数在编译器中对应着一个Op(Operator);

var builtinFuncs = [...]struct {
name string
op   Op
}{
{"append", OAPPEND},
{"cap", OCAP},
{"close", OCLOSE},
{"complex", OCOMPLEX},
{"copy", OCOPY},
{"delete", ODELETE},
{"imag", OIMAG},
{"len", OLEN},
{"make", OMAKE},
{"new", ONEW},
{"panic", OPANIC},
{"print", OPRINT},
{"println", OPRINTN},
{"real", OREAL},
{"recover", ORECOVER},
}

len函数对应的Op为OLEN;

??在cmd\compile\internal\gc\syntax.go 语法树相关的定义中我们亦可看到OLEN的定义;

??len函数支持获取多种类型变量的长度或容量,这也就说明了该函数的实现可能不只有一种或许每种类型对应着一种实现;

??len函数支持的类型有:string、array、slice、map,chan;从中我们可以简单把类型分为两类:string、数组为长度固定的,slice、map、chan为动态长度的。针对固定长度类型len是当作常量来实现的;

len对于固定长度类型的实现:

??在编译器的源码cmd\compile\internal\gc\const.go中我们可以发现evconst函数有这样一段代码;

func evconst(n *Node) {
   ...
 // Pick off just the opcodes that can be constant evaluated.
switch op := n.Op; op {
case OCAP, OLEN:
	fmt.Println("const:",nl,nl.Type.Etype)
	switch nl.Type.Etype {
	case TSTRING:
		if Isconst(nl, CTSTR) {
			setintconst(n, int64(len(strlit(nl))))
		}
	case TARRAY:
		if !hascallchan(nl) {
			setintconst(n, nl.Type.NumElem())
		}
	}
...
}
...
}

??这段代码中可以看到针对string类型是直接获取nl的长度放入到Node当中的,该节点为AST的literal节点。此处的nl为len所接收的字符串;

??针对数组类型也类似直接获取数组的长度写入常量;

??此处所写入的值也就是len函数所返回的值;

len对动态长度类型的的实现:

??在编译器源码cmd\compile\internal\gc\ssa.go中有这么一段代码:

// expr converts the expression n to ssa, adds it to s and
returns the ssa result.
func (s *state) expr(n *Node) *ssa.Value {
...
case OLEN, OCAP:
	switch {
	case n.Left.Type.IsSlice():
		op := ssa.OpSliceLen
		if n.Op == OCAP {
			op = ssa.OpSliceCap
		}
		v:= s.newValue1(op, types.Types[TINT], s.expr(n.Left))
		fmt.Println("ssa...",v.LongString(),"-",n.Left.Op)
		return v
	case n.Left.Type.IsString(): // string; not reachable for OCAP
		v:=s.newValue1(ssa.OpStringLen, types.Types[TINT], s.expr(n.Left))
		fmt.Println("string...",v.LongString(),n.Left.Op)
		return v
	case n.Left.Type.IsMap(), n.Left.Type.IsChan():
		return s.referenceTypeBuiltin(n, s.expr(n.Left))
	default: // array
		fmt.Println("array:",n.Left.Type.NumElem())
		return s.constInt(types.Types[TINT], n.Left.Type.NumElem())
	}
...
}

??从中可以看到针对各种类型的处理,此处也有string与array类型的处理但并未执行到,未发现起到了作用,如知道请告知;

??针对slice类型此处转成了OpSliceLen操作,在 builtin优化阶段将 通过 (SliceLen (SliceMake _ len _)) -> len直接替换为slice的长度,此处调用的代码为:cmd\compile\internal\ssa\rewritegeneric.go中的rewriteValuegeneric_OpSliceLen函数;

??针对map/chan类型,此处调用了referenceTypeBuiltin函数。

参考资料:

https://github.com/golang/go

文章首发地址:Solinx

https://mp.weixin.qq.com/s/iO5qjcCql-MPJiatUtdiHQ

原文地址:https://www.cnblogs.com/softlin/p/12547393.html

时间: 2024-10-09 00:32:27

Golang中的内置函数的相关文章

python中的内置函数getattr()

在python的官方文档中:getattr()的解释如下: getattr(object, name[, default]) Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For examp

JavaScript中的内置函数

JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供的. JavaScript中的内置函数如下表所示: 函     数 说     明 eval() 求字符串中表达式的值 isFinite() 判断一个数值是否为无穷大 isNaN() 判断一个数值是否为NaN parseInt() 将字符串型转换为整型 parseFloat() 将字符串型转换为浮点

Kettle中JavaScript内置函数说明

本文链接:https://blog.csdn.net/u010192145/article/details/102220563 我们在使用JavaScript组件的时候,在左侧核心树对象栏中可以看到Kettle为我们提供了很多简洁强大的内置函数,帮助我们在写脚本的时候对数据.参数变量等能很轻松的做处理,体验编码的感觉.本篇将详细介绍JavaScript组件中的函数功能 脚本组件包含的函数主要包括六大类,分别是: 字符串类型的函数(String Functions) 浮点型的函数(Numeric

8. Smarty3:模版中的内置函数

smarty3中对内置函数的改动比较大,添加了许多新的功能:变量声明,表达式,流程控制,函数,数组等.但是建议不要在模版中去使用过于复杂的逻辑,而是要尽量将一些程序设计逻辑写到PHP中,并在模版中采用非常简单的语法即可调用.通常只在模版中进行一些如变量输出,流程判断及数组遍历等操作即可. 1. 变量声明 在模版中声明变量或用来在模版运行时为模版变量赋值,这是在Smarty3中新增的功能. 使用{assign},在模版运行时为模版变量或数组元素赋值 和在赋值时使用一些表达式 {$var=...}是

Python中常用内置函数介绍(filter,map,reduce,apply,zip)

Python是一门很简洁,很优雅的语言,其很多内置函数结合起来使用,可以使用很少的代码来实现很多复杂的功能,如果同样的功能要让C/C++/Java来实现的话,可能会头大,其实Python是将复杂的数据结构隐藏在内置函数中,只要写出自己的业务逻辑Python会自动得出你想要的结果.这方面的内置函数主要有,filter,map,reduce,apply,结合匿名函数,列表解析一起使用,功能更加强大.使用内置函数最显而易见的好处是: 1. 速度快,使用内置函数,比普通的PYTHON实现,速度要快一倍左

Python中max()内置函数使用(list)

在学习完列表和元组的基础知识后,做到一个题: 求出列表中频次出现最多的元素. 学习到了python内置函数max的用法 其参数key的用法 匿名函数lamda的用法 python内置函数max() max()方法返回给定参数的最大值,参数值可为序列. 1 print ("max(80, 100, 1000) : ", max(80, 100, 1000)) 2 print ("max(-20, 100, 400) : ", max(-20, 100, 400)) 3

查看python 3中的内置函数列表,以及函数功能描述

1 >>> dir(__builtins__)//查看内置函数(BIF)列表 2 ['ArithmeticError', 'AssertionError', 'AttributeError', 3 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 4 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionE

Python中的内置函数__init__()的理解

有点意思,本来我是学习java的.总所周知,java也有构造函数,而python在面向对象的概念中,也有构造函数.它就是 __init__(self) 方法. 其实类似于__init__()这种方法,其实还有很多.类似__del__(self)  ...  __new__(cls,*args,**kwd) 等等.它们被成为 python的常用内置方法. 下面开始介绍一下我对 __init__()的理解: class A(object): def __init__(self,name):  sel

python中的内置函数getattr()介绍及示例

在python的官方文档中:getattr()的解释如下: ? 1 2 3 getattr(object, name[, default]) Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object's attributes, the result is the value of that attribute. F