1

GO语言实战之函数与方法

 1 year ago
source link: https://liruilongs.github.io/2022/03/11/Go/GO%E8%AF%AD%E8%A8%80%E5%AE%9E%E6%88%98%E4%B9%8B%E5%87%BD%E6%95%B0%E4%B8%8E%E6%96%B9%E6%B3%95/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

GO语言实战之函数与方法

摘要
首页显示摘要内容(替换成自己的)


  • 嗯,学习GO,所以有了这篇文章
  • 博文部分内容为《GO语言实战》读书笔记之一
  • 主要涉及知识

傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波


对于这个概念小伙伴一定不陌生,常用的脚本语言中一般都会用,通过函数来整合一些逻辑上耦合性较强的代码块,从而提高代码的可读性,可复用性。

GO语言中的函数语法格式和其他语言略有不同,函数可以先使用后定义,同时go支持闭包,拆包,异常信息返回等

func funcName(param paramType)(returnVal1 returnType, err error){
// do something
}
package main

import (
"fmt"
"time"
)

func main() {
nowTime := time.Now()
fmt.Println(nowTime.Format("2006-01-02 15:04:05"))
// 拆包
i, j := func_demo()
//调用有参函数
func_demos("你好,世界!")
fmt.Println(i, j)
// 匿名函数
get_func_demo := func(x int) int {
return x
}
fmt.Println(get_func_demo(3))
// 闭包
f := get_func_()
fmt.Println(f())
}
// 拆包
func func_demo() (int, int) {
fmt.Println("你好,世界!")
return 1, 2
}
// 接收参数
func func_demos(mes string) {
fmt.Println(mes)
}
// 闭包
func get_func_() (func() int){
i := 1
return func() (int) {
i+=1
return i
}
}
============
2022-04-14 10:01:03
你好,世界!
你好,世界!
1 2
3
2

其他的脚本语言对比

对于Shell脚本来说,shell脚本中的函数只能先定义后使用,函数可以看做是一个微小版的shell脚本,功能语法相对简单

#!/bin/bash

# 带关键字定义
function f(){
echo $(date)
}
f

# 直接函数名的方式定义
func_name(){
echo "Hello,Word!"
}
func_name

# 接受入参
func_names(){
echo "${0}"
echo "${1}"
}
func_names 5

# 返回数组
func_array(){
my_array=("liruilong" 1 2 3)
echo ${my_array[*]}
}
retuens=($(func_array))
echo "${retuens[*]}"

# 返回信号
func_return(){
return 1
}
func_return

===========================
2022年 04月 14日 星期四 10:36:20 CST
Hello,Word!
fun.sh
5
liruilong 1 2 3

对于Python来讲,函数也必须先定义后使用。python的函数语法要多一点,支持可变参数,关键字参数,缺省参数,同时支持拆包,闭包等

#!/usr/bin/python3
# -*- coding: UTF-8 -*-


def func_demo():
print("Hello,Word")
func_demo()

def func_param(a,b,c=","):
print(a,c,b)
func_param("Hello","Word")
func_param(b="Word",a="Hello")

def func_return():
return 2
print(func_return())


def func_arges(a,*arges):
for i in arges:
print(i)
func_arges(1,2,3)
func_arges(1)


def func_aeges_(**arges):
print(arges)
func_aeges_(name='liruilong', age=18, id=110)

def return_num():
return 100, 200
num1, num2 = return_num()
==========================
Hello,Word
Hello , Word
Hello , Word
2
2
3
{'name': 'liruilong', 'age': 18, 'id': 110}

关于函数介绍到这里,来看看方法,GO语言中方法实际上也是函数,只是在声明时,在关键字func方法名之间增加了一个参数

在面向对象里,方法是类行为和对象行为的体现(类方法和实例方法),GO不是面向对象类型的语言,但是Go方法和java中的方法类似,同样不能单一存在,必须要绑定。

Java中的方法

/**
* @Classname Function
* @Description TODO
* @Date 2022/4/14 23:09
* @Created LiRuilong
*/
public class Function {
String str;
// 对象方法
public String getStr(){
return str;
}
// 类方法
public static Function build(){
return new Function();
}

public static void main(String[] args) {
System.out.println("Hello,Word!");
}
}

java中方法必定是和或者对象绑定的,和类绑定的方法被称为静态方法,和对象绑定的为实例方法。GO中的方法必须要和接收者绑定,那GO中的所谓的接收者又是什么?,即用户定义的类型,听着有些别扭,类比C中我们常讲的结构体

用户定义的类型(结构体)

Go 语言允许用户定义类型(结构体)。当用户声明一个新类型时,这个声明就给编译器提供了一个框架,告知必要的内存大小表示信息

Go 语言里声明用户定义的类型有两种方法。最常用的方法是使用关键字 struct,它可以让用户创建一个结构类型

结构里每个字段都会用一个已知类型声明。这个已知类型可以是内置类型,也可以是其他用户定义的类型

  • 声明一个结构类型

    type user struct {
    name string
    email string
    }

  • 使用结构类型声明变量,并初始化为其零值

    var bill user

    当声明变量时,这个变量对应的值总是会被初始化。这个值要么用指定的值初始化,要么用零值(即变量类型的默认值)做初始化

  • 对数值类型来说,零值是 0

  • 对字符串来说,零值是空字符串

  • 对布尔类型,零值是 false

:=:一个短变量声明操作符在一次操作中完成两件事情:声明一个变量,并初始化

  • 使用结构字面量来声明一个结构类型的变量
    lisa := user{
    name: "liruilong",
    email: "[email protected]"
    }
  • 使用结构字面量创建结构类型的值
    user{
    name: "liruilong",
    email: "[email protected]"
    }
  • 不使用字段名,创建结构类型的值,这种形式下,值的顺序很重要,必须要和结构声明中字段的顺序一致。
    user{"Bill", "[email protected]"}

当声明结构类型时,字段的类型并不限制在内置类型,也可以使用其他用户定义的类型

  • 使用其他结构类型声明字段

    type admin struct{
    liruilong user,
    leve string
    }
    fred := admin{
    liruilong: user{"Bill", "[email protected]"},
    level: "super",
    }

    另一种声明用户定义的类型的方法是,基于一个已有的类型,将其作为新类型的类型说明

  • 基于 int64 声明一个新类型

    type Duration int64

    Duration 是一种描述时间间隔的类型,单位是纳秒(ns)。这个类型使用内置的 int64 类型作为其表示

我们把 int64 类型叫作 Duration 的基础类型,Go 并不认为 Duration 和 int64 是同一种类型。这两个类型是完全不同的有区别的,这里和有些面向对象的语言有很大的区别。

  • 给不同类型的变量赋值会产生编译错误
    package main

    import (
    "fmt"
    )
    type Duration int64

    func main() {
    var dur Duration
    //正确写法 ur = Duration(1000)
    dur = int64(1000)
    fmt.Println(dur)
    }

    ============
    [Running] go run "d:\GolandProjects\code-master\demo\hello.go"
    # command-line-arguments
    demo\hello.go:10:6: cannot use int64(1000) (type int64) as type Duration in assignment

    [Done] exited with code=2 in 0.705 seconds
    OK,了解了GO中的结构体,我们来看看方法

GO中,通过方法能给用户定义的类型也就是俗称的结构体添加新的行为。声明时,func方法名之间增加了一个结构体参数
我们把关键字func和函数名之间的参数被称作接收者,将函数接收者的类型绑在一起。如果一个函数有接收者,这个函数就被称为方法。

Go 语言里有两种类型的接收者:值接收者,指针接收者

使用值接收者声明一个方法

// notify 使用值接收者实现了一个方法
func (u user) notify() {
fmt.Printf("Sending User Email To %s<%s>\n",
u.name,
u.email)
}

如果使用值接收者声明方法调用时会使用这个值的一个副本来执行。使用 bill 的值作为接收者进行调用,方法 notify 会接收到 bill 的值的一个副本。

// user 类型的值可以用来调用使用值接收者声明的方法
bill := user{"Bill", "[email protected]"}
bill.notify()

也可以使用指针来调用使用值接收者声明的方法,使用指向 user 类型值的指针来调用 notify 方法

   // 指向 user 类型值的指针也可以用来调用使用值接收者声明的方法
lisa := &user{"Lisa", "[email protected]"}
lisa.notify() //(*lisa).notify()

指针被解引用为值,不管是变量调用还是指针调用,notify 操作的都是一个副本。

使用指针接收者声明一个方法

// changeEmail 使用指针接收者实现了一个方法
func (u *user) changeEmail(email string) {
u.email = email
}

使用指针接收者声明。这个接收者的类型是指向 user 类型值的指针,而不是 user 类型的值。当调用使用指针接收者声明的方法时,这个方法会共享调用方法时接收者所指向的值

这一点和使用值接收有很大的区别,某种意义上讲,使用值接收一般用于消费,使用指针接收,一般用于生产加工修饰。

lisa := &user{"Lisa", "[email protected]"}
// 指向 user 类型值的指针可以用来调用使用指针接收者声明的方法
lisa.changeEmail("[email protected]")
lisa.notify()

值接收者使用值的副本来调用方法,而指针接受者使用实际值来调用方法。

bill := user{"Bill", "[email protected]"}
// user 类型的值可以用来调用使用指针接收者声明的方法
bill.changeEmail("[email protected]")
bill.notify() //(&bill).changeEmail ("[email protected]")

Go语言既允许使用值,也允许使用指针来调用方法,不必严格符合接收者的类型

// 声明 并使用方法
package main

import (
"fmt"
)

// user 在程序里定义一个用户类型
type user struct {
name string
email string
}

// notify 使用值接收者实现了一个方法,一般用于消费对象
func (u user) notify() {
fmt.Printf("Sending User Email To %s<%s>\n",
u.name,
u.email)
}

// changeEmail 使用指针接收者实现了一个方法,一般用于生产加工对象
func (u *user) changeEmail(email string) {
u.email = email
}

// main 是应用程序的入口
func main() {
// user 类型的值可以用来调用使用值接收者声明的方法
bill := user{"Bill", "[email protected]"}
bill.notify()

// 指向 user 类型值的指针也可以用来调用使用值接收者声明的方法
lisa := &user{"Lisa", "[email protected]"}
lisa.notify()

// user 类型的值可以用来调用使用指针接收者声明的方法
bill.changeEmail("[email protected]")
bill.notify()

// 指向 user 类型值的指针可以用来调用使用指针接收者声明的方法
lisa.changeEmail("[email protected]")
lisa.notify()
}
================
[Running] go run "d:\GolandProjects\code-master\chapter5\listing11\tempCodeRunnerFile.go"
Sending User Email To Bill<[email protected]>
Sending User Email To Lisa<[email protected]>
Sending User Email To Bill<[email protected]>
Sending User Email To Lisa<[email protected]>

[Done] exited with code=0 in 2.288 seconds

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK