go语言中op函数 go语言 oop

Go语言文件操作本文主要介绍go语言中op函数了Go语言中文件读写的相关操作 。
文件是什么?
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合go语言中op函数,文件分为文本文件和二进制文件 。
os.Open() 函数能够打开一个文件go语言中op函数,返回一个 *File 和一个 err。对得到的文件实例调用 close() 方法能够关闭文件 。
为了防止文件忘记关闭,我们通常使用defer注册文件关闭语句 。
Read方法定义如下go语言中op函数:
它接收一个字节切片,返回读取的字节数和可能的具体错误,读到文件末尾时会返回 0 和 io.EOF。举个例子:
使用for循环读取文件中的所有数据 。
bufio是在file的基础上封装了一层API , 支持更多的功能 。
io/ioutil 包的 ReadFile 方法能够读取完整的文件,只需要将文件名作为参数传入 。
os.OpenFile() 函数能够以指定模式打开文件,从而实现文件写入相关功能 。
其中:
【go语言中op函数 go语言 oop】name :要打开的文件名flag :打开文件的模式 。模式有以下几种:
perm :文件权限 , 一个八进制数 。r(读)04 , w(写)02,x(执行)01 。
为什么我不会舍弃Python投奔Go语言在Go语言中,规定的方式是,函数返回错误信息 。这没什么 。如果一个文件并不存在,op.Open函数会返回一个错误信息 。这没什么 。如果你向你一个中断了的网络连接里写数据,net.Conn里的Write方法会返回一个错误 。这没什么 。这种状况在这种程序中是可以预料到的 。这种操作就是容易失败,你知道程序会如何运行 , 因为API的设计者通过内置了一种错误情况的结果而让这一切显得很清楚 。
从另一方面讲 , 有些操作基本上不会出错 , 所处的环境根本不可能给你提示错误信息 , 不可能控制错误 。这才是让人痛苦的地方 。典型的例子;一个程序执行
x[j],j值超出数组边界,这才痛苦 。像这样预料之外的麻烦在程序中是一个严重的bug,一般会弄死程序的运行 。不幸的是,由于这种情况的存在,我们很难写出健壮的,具有自我防御的服务器——例如,可以应付偶然出现的有bug的HTTP请求处理器时,不影响其他服务的启动和运行 。为解决这个问题,我们引入了恢复机制,它能让一个go例程从错误中恢复,服务余下设定的调用 。然而,代价是,至少会丢失一个调用 。这是特意而为之的 。引用邮件中的原话:“这种设计不同于常见的异常控制结构 , 这是一个认真思考后的决定 。我们不希望像java语言里那样把错误和异常混为一谈 。”
我刚开始提到的那篇文章里问“为什么数组越界造成的麻烦会比错误的网址或断掉的网络引出的问题要大?”答案是,我们没有一种内联并行的方法来报告在执行x[j]期间产生的错误 , 但我们有内联并行的方法报告由错误网址或网络问题造成的错误 。
使用Go语言中的错误返回模式的规则很简单:如果你的函数在某种情况下很容易出错 , 那它就应该返回错误 。当我调用其它的程序库时,如果它是这样写的,那我不必担心那些错误的产生,除非有真正异常的状况,我根本没有想到需要处理它们 。
有一个你需要记在心里的事情是,Go语言是为大型软件设计的 。我们都喜欢程序简洁清晰,但对于一个由很多程序员一起开发的大型软件,维护成本的增加很难让程序简洁 。异常捕捉模式的错误处理方式的一个很有吸引力的特点是,它非常适合小程序 。但对于大型程序库,如果对于一些普通操作,你都需要考虑每行代码是否会抛出异常、是否有必要捕捉处理,这对于开发效率和程序员的时间来说都是非常严重的拖累 。我自己做开发大型Python软件时感受到了这个问题 。
Go语言的返回错误方式,不可否认,对于调用者不是很方便,但这样做会让程序中可能会出错的地方显的很明显 。对于小程序来说,你可能只想打印出错误,退出程序 。对于一些很精密的程序,根据异常的不同,来源的不同 , 程序会做出不同的反应,这很常见,这种情况中,try
catch的方式相对于错误返回模式显得冗长 。当然,Python里的一个10行的代码放到Go语言里很可能会更冗长 。毕竟,Go语言主要不是针对10行规模的程序的 。
就是要说明这一点:Go语言程序员认为,把error作为一种内置的类型是非常重要的 。
如何看待go语言泛型的最新设计?Go 由于不支持泛型而臭名昭著 , 但最近,泛型已接近成为现实 。Go 团队实施了一个看起来比较稳定的设计草案,并且正以源到源翻译器原型的形式获得关注 。本文讲述的是泛型的最新设计,以及如何自己尝试泛型 。
例子
FIFO Stack
假设你要创建一个先进先出堆栈 。没有泛型,你可能会这样实现:
type Stack []interface{}func (s Stack) Peek() interface{} {
return s[len(s)-1]
}
func (s *Stack) Pop() {
*s = (*s)[:
len(*s)-1]
}
func (s *Stack) Push(value interface{}) {
*s =
append(*s, value)
}
但是,这里存在一个问题:每当你 Peek 项时,都必须使用类型断言将其从 interface{} 转换为你需要的类型 。如果你的堆栈是 *MyObject 的堆栈,则意味着很多 s.Peek().(*MyObject)这样的代码 。这不仅让人眼花缭乱 , 而且还可能引发错误 。比如忘记 * 怎么办?或者如果您输入错误的类型怎么办?s.Push(MyObject{})` 可以顺利编译,而且你可能不会发现到自己的错误,直到它影响到你的整个服务为止 。
通常 , 使用 interface{} 是相对危险的 。使用更多受限制的类型总是更安全 , 因为可以在编译时而不是运行时发现问题 。
泛型通过允许类型具有类型参数来解决此问题:
type Stack(type T) []Tfunc (s Stack(T)) Peek() T {
return s[len(s)-1]
}
func (s *Stack(T)) Pop() {
*s = (*s)[:
len(*s)-1]
}
func (s *Stack(T)) Push(value T) {
*s =
append(*s, value)
}
这会向 Stack 添加一个类型参数,从而完全不需要 interface{} 。现在,当你使用 Peek() 时,返回的值已经是原始类型 , 并且没有机会返回错误的值类型 。这种方式更安全,更容易使用 。(译注:就是看起来更丑陋 , ^-^)
此外,泛型代码通常更易于编译器优化,从而获得更好的性能(以二进制大小为代价) 。如果我们对上面的非泛型代码和泛型代码进行基准测试,我们可以看到区别:
type MyObject struct {
X
int
}
var sink MyObjectfunc BenchmarkGo1(b *testing.B) {
for i := 0; ib.N; i{
var s Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek().(MyObject)
}
}
func BenchmarkGo2(b *testing.B) {
for i := 0; ib.N; i{
var s Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek()
}
}
结果:
BenchmarkGo1BenchmarkGo1-161283752887.0 ns/op48 B/op2 allocs/opBenchmarkGo2BenchmarkGo2-162840647941.9 ns/op24 B/op2 allocs/op
在这种情况下 , 我们分配更少的内存,同时泛型的速度是非泛型的两倍 。
合约(Contracts)
上面的堆栈示例适用于任何类型 。但是 , 在许多情况下,你需要编写仅适用于具有某些特征的类型的代码 。例如,你可能希望堆栈要求类型实现 String() 函数
关于go语言中op函数和go语言 oop的介绍到此就结束了 , 不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。

    推荐阅读