Golang学习(十九) 方法

        在上一节,我们学习了定义一个结构体,比如一只猫,它有自己的名字、年龄、花色,然而这些都是一些静态信息,猫猫还会有很多的行为动作,比如奔跑、恰饭、鄙视你等等,而这些动作的实现就依赖于方法了

      golang中的方法是作用在指定的数据类型上的。 即:和指定的数据类型绑定,因此自定义的数据类型都可以有方法,不仅仅是结构体有)

方法声明的格式

func (变量 自定义数据类型) 方法名(){
   代码块
}

案例

package main

import (
	"fmt"
)

type Person struct{
	Num int
}


func (p Person) test(){    //这里的意思是将test这个方法绑定了Person的结构体
	fmt.Println(p.Num)     //可以通过调用Person结构体来引用方法
}

func main(){
	var p Person = Person{10}  //声明结构体

	p.test()   //因为上面Person结构体绑定了test方法,所以可以直接通过"."来调用方法,
	           //在调用该方法时,会将main下的p变量传参到test方法中绑定的Person结构体前面的形参上

}

  返回

10

小结

1. test方法和Person类型进行绑定
2. test方法只能通过Person类型的变量来调用,而不能直接调用,也不能用其他类型的变量来调用
3. main中 p 变量的名称不需要和func 方法定义传参一样
4. func 方法中p 表示那个Person变量调用,这个p就是他的一个副本 值传递,方法中的操作不会影响外部的值,因为这是他的副本值拷贝
5. func 方法中的p 可以自定义

一、快速入门

给Person结构体绑定一个"speak"方法,调用该方法输出"xxx是一个好人"

package main

import (
	"fmt"
)

type Person struct{
	Name string
}


func (p Person) test(){
	fmt.Println(p.Name)
}

//添加speak 方法
func (p Person) speak(){
	fmt.Printf("%v 是一个好人",p.Name)
}

func main(){
	var p Person = Person{"test"}
	p.speak()   //调用方法
}

案例1 调用方法打印矩形

编写结构体MethodUtils  编写一个方法,不需要字段,在方法中打印一个10*8的矩形,在main方法中调用该方法

package main

import "fmt"

type MethodUtils struct {
	 //结构体 可以不写字段也可以使用
}


func (mu MethodUtils) Print(){
	for i := 0; i < 10;i++{
		for k :=0; k < 8; k++{
			fmt.Print("*")
		}
		fmt.Println()
	}
}


func main() {
	mu := MethodUtils{}
	mu.Print()
}

 返回

********
********
********
********
********
********
********
********
********
********

 案例2 给定方法参数打印矩形

编写一个方法,提供m和n的参数,输出一个m*n的矩形

package main

import "fmt"

type MethodUtils struct {
	//可以不写字段也可以使用
}

func (mu MethodUtils) Print(m int,n int){  //给方法设置接收值
	for i := 0; i < m;i++{
		for k :=0; k < n; k++{
			fmt.Print("*")
		}
		fmt.Println()
	}
}


func main() {
	mu := MethodUtils{}
	mu.Print(10 , 81)   //在调用函数时传入参数
}

 案例3  编写方法计算矩形面积

编写一个方法 算该矩形的面积,将其作为方法返回值。在main方法中调用该方法,接收返回的面积值,并打印

package main

import "fmt"

type MethodUtils struct {
	//可以不写字段也可以使用
}


func (mu MethodUtils) area(len float64, width float64) (mianji float64) { //设置返回值类型为float64
	mianji =  len * width                                                 //当返回值有具体的变量名称时需要圆括号括起来
	return
}


func main() {
	mu := MethodUtils{}
	areaRes := mu.area(2.5 , 8.3)
	fmt.Println("面积为", areaRes)
}

 案例4 定义方法判断奇数偶数

编写一个方法,判断一个数是奇数还是偶数

package main

import "fmt"

type MethodUtils struct {
	//可以不写字段也可以使用
}


func (mu *MethodUtils) JudgeNum(num int){  //为了使得我们这个方法可以修改外部的值
	if num % 2 == 0 {                      //所以这里将类型设置为指针类型
		//如果整除以2 等于0 那么就是整数
		fmt.Println("偶数")
	}else {
		fmt.Println("奇数")
	}
}


func main() {
	mu := MethodUtils{}   //我们上面方法说明接收的类型是一个指针类型
	mu.JudgeNum(13)  //正常应该写(&mu).JudgeNum(13) 来调用的
	                       //但编辑器做了优化,不用写也是可以用的

	(&mu).JudgeNum(13)  //两种方法都写上

}

 返回

奇数
奇数

 案例5  编写方法打印指定行列字符

根据行、列、字符打印对应行数和列数的字符  比如  行3  列2  字符"s"

package main

import "fmt"

type MethodUtils struct {
	//可以不写字段也可以使用
}



func (mu *MethodUtils) Print(n int, m int , key string){
	for i := 1; i <= n; i++{
		for j := 1; j <= m; j++{
			fmt.Print(key)
		}
		fmt.Println()
	}
}


func main() {
	mu := MethodUtils{}

	mu.Print(7,3,"sss")
}

返回

sssssssss
sssssssss
sssssssss
sssssssss
sssssssss
sssssssss
sssssssss

 案例6  定义方法实现加减乘除

定义一个小小计算器的结构体(Calcuator) 实现加减乘除的功能

package main

import "fmt"

//计算机要传入两个数,
//方法1  写入结构体, 在结构体中定义两个数据类型 xxx int
//然后传参给结构体,在调用方法时使用

//方法2  直接在方法中设置传参,直接调用变量



type Calcuator struct {
	Num1 float64
	Num2 float64
}


func (calcuator *Calcuator) getSum(operator byte) float64 {
	res := 0.0
	switch operator {
	case '+':
		res = calcuator.Num1 + calcuator.Num2
	case '-':
		res = calcuator.Num1 - calcuator.Num2
	case '*':
		res = calcuator.Num1 * calcuator.Num2
	case '/':
		res = calcuator.Num1 / calcuator.Num2
	default:
		fmt.Println("运算符输入有误")

	}
	return res
}




func main() {

	calcuator := Calcuator{}
	calcuator.Num1 = 1.2
	calcuator.Num2 = 2.2


	res := calcuator.getSum('*')  //在传参时提供一个运算符
	fmt.Println("res",res)

}

返回

res 2.64

案例7 九九乘法表 封装为方法

先实现99乘法表

package main

import "fmt"

func main()  {
	for i := 1; i < 10; i++ {

		for k := 1 ; k <= i; k++ {
			fmt.Print(k ,"*", i , "=",i * k," ")
		}
		fmt.Println()
	}
}

 封装

package main

import "fmt"

type MethodUtils struct {
	max int
}


func (methodUtils MethodUtils) jiujiu(max int) {
	//将上限设置为max的最大值
	for i := 1; i <= max; i++ {
		for k := 1; k <= i; k++ {
			fmt.Print(k, "*", i, "=", i*k, " ")
		}
		fmt.Println()
	}
}


func main()  {
	methodUtils := MethodUtils{}
	methodUtils.jiujiu(9)    //调用

}

 返回

1*1=1 
1*2=2 2*2=4 
1*3=3 2*3=6 3*3=9 
1*4=4 2*4=8 3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 


//可以通过指定上限值来定义打印到多少上限

二、方法和函数的区别

1、函数  可以使用函数名称(实参列表) 来调用
  方法  需要先指定一个变量,一个与方法绑定的变量(实参)进行调用

2.对于普通函数,接收者为值类型时,不能将指针类型的数据之间传递,反之亦然 

3. 对于方法(如 struct 的方法) 接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样可以

案例1 函数不支持 值与指针的传递

package main

import "fmt"



type Person struct {
	Name string
}


func test01(p Person){   //对于普通函数,接收者为值类型时,不能将指针类型的数据之间传递,反之亦然
	fmt.Println(p.Name)
}

func main(){
	p := Person{"tom"}
	test01(p)

	test01(&p)       //报错了, 因为在函数中,如果没有定义接收的值是一个指针,那么是无法传递一个地址的
}

案例2 方法支持 值与指针的传递


package main

import "fmt"

type Person struct {
	Name string
}


func (p Person) test03() {    //可以看到,我这里使用值类型的变量
	                          // 对于方法(如 struct 的方法) 接收者为值类型时,可以直接用指针类型的变量调用方
	                          //反过来同样可以,意思是下面调用的时候&p是可以的,这里的p *Person定义都是成功的
	                          //即可以使用指针类型传,也可以使用值类型传
	p.Name = "jack"
	fmt.Println(p.Name)
}

func main(){
	p := Person{"tom"}

	p.test03()     //我们发现这里可以使用值传递 和 指针传递  效果是一样的
	(&p).test03()  //这里的(&p) 和函数不同,他也是值拷贝,方法


	fmt.Println(p.Name)  //输出全局的变量
}

总结

不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和那个类型绑定的
如果是和值类型绑定的,比如 (p Persion)则是值拷贝, 如果是和值类型,比如(p *Person)则是地址拷贝

小练习

1、学生案例

1. 编写一个Student的结构体,包含name、gender、age、id、score字段,分别为string、string、int、int、float64类型
2. 结构体中声明一个say方法,返回string类型,方法返回信息中包含所有字段值
3. 在main方法中,创建Student结构体实例(变量),并访问say方法,并将调用结果打印输出

代码

package main

import "fmt"

type Student struct {
	name string
	gender string
	age int
	id int
	score float64
}

//Printf 和Sprintf的区别
//Printf用传入的格式化规则符将传入的变量写入到标准输出里面(即在终端中有显示),
//用传入的格式化规则符将传入的变量格式化,(终端中不会有显示)  返回为 格式化后的字符串。
func (student Student) say() string  {
	infoStr := fmt.Sprintf("student的信息 name=[%v] gender=[%v] age=[%v] id=[%v] score=[%v]",
		student.name,student.gender,student.age,student.id,student.score)
	return infoStr
}

func main(){
	student :=Student{
		name: "tom",
		gender : "male",
		age : 18,
		id : 1000,
		score : 99.98,
	}
	str := student.say()
	fmt.Println(str)

}

2、盒子案例

1. 编程创建一个Box结构体,在其中声明三个字段,表示一个立方体的长、宽、搞,长宽高从终端获取
2. 声明一个方法获取立方体的体积
3. 创建一个Box 结构体变量,打印给定尺寸的立方体的体积

代码

package main

import "fmt"

type Box struct {
	len float64
	width float64
	height float64
}


func (box *Box) getVolumn() float64  {
	return box.len * box.width * box.height
}

func main(){
	box := Box{}
	box.len = 1.1
	box.width = 2.0
	box.height = 3.0
	volumn := box.getVolumn()
	fmt.Printf("%.2f",volumn)

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值