Golang接口上的指针接收器和值接收器

时间:2018-12-10 07:50:47

标签: go

这个问题并不像我想的那么明确,我会问一个更好的问题。但是我不想在此标记重复。因此,我已提出自己的问题。如果可以,可以将其删除以免混淆社区。请只做那些需要的。当您在这里时,请不要对我投反对票。抱歉,不清楚

我是golang的新手,刚掌握了它。

我正在学习环游,然后以我自己的理解来使用它。 我当时在Interfaces并开始以自己的理解实施。 这是Go PlayGround Link

步骤1:我将3种类型分别设为int,struct和interface

package main

import (
    "fmt"
)

type MyInt int

type Pair struct {
    n1, n2 int
}

type twoTimeable interface {
    result() (int, int)
}

第2步:然后我为指针接收器实现twoTimeable,因为它更改了基础值。

func (p *Pair) result() (int, int) {
    p.n1 = 2 * p.n1
    p.n2 = 2 * p.n2
    return p.n1, p.n2
}

func (m *MyInt) result() (int, int) {
    *m = 2 * (*m)
    return int(*m), 0
}

步骤3:然后,我在主函数中声明并分配了MyInt,Pair及其对应的指针。我还声明了twoTimeable接口

mtemp := MyInt(2)
var m1 MyInt
var m2 *MyInt
var p1 Pair
var p2 *Pair
m1, m2, p1, p2 = MyInt(1), &mtemp, Pair{3, 4}, &Pair{5, 6}
var tt twoTimeable

fmt.Println(" Values  : ", m1, *m2, p1, *p2, tt)

步骤4:我分配了MyInt,Pair及其指针(称为实现的方法)并打印出来。

tt = m1
fmt.Println(tt.result())
fmt.Printf("Value of m1 %v\n", m1)

tt = m2
fmt.Println(tt.result())
fmt.Printf("Value of m2 %v\n", *m2)

tt = p1
fmt.Println(tt.result())
fmt.Printf("Value of p1 %v\n", p1)

tt = p2
fmt.Println(tt.result())
fmt.Printf("Value of p2 %v\n", *p2)

显示错误:

prog.go:41:5: cannot use m1 (type MyInt) as type twoTimeable in assignment:
    MyInt does not implement twoTimeable (result method has pointer receiver)
prog.go:49:5: cannot use p1 (type Pair) as type twoTimeable in assignment:
    Pair does not implement twoTimeable (result method has pointer receiver)

我也读过this question,我知道m1和p1无法寻址,这就是为什么它无法编译的原因。 但是如果我使用p1或m1 p1/m1.result()(自动取消引用FTW),方法result()就会很好地工作

现在在第2步中,将指针接收器更改为值接收器,并将* m更改为m(我知道Output的更改)

func (p Pair) result() (int, int) {
    p.n1 = 2 * p.n1
    p.n2 = 2 * p.n2
    return p.n1, p.n2
}

func (m MyInt) result() (int, int) {
    m = 2 * (m)
    return int(m), 0
}

它突然不显示编译错误。不适用于m2和p2,因为现在没有使用* MyInt和* Pair

的结果实现

这意味着如果接口方法实现具有值接收器,则tt可以容纳指针和值。 但是,当接口方法实现具有指针接收器时,它将无法保存非指针。

  

Q1:为什么可以在值接收器接口方法(p MyInt)result()上使用指针(tt = m2),而不在指针接收器接口方法(p * MyInt)result()上使用值(tt = m1)很好)。

现在,让我们返回指针接收器。

  

是否存在一种方法,如果函数接受参数(ttTwoTimeable),则无论tt是否为类型指针,我都可以调用tt.result(),因为result()仅由指针接收器定义。

请参见下面的代码:

func doSomething(tt twoTimeable) {
    temp1, temp2 := tt.result()
    fmt.Print("doing something with ", temp1, temp2)
} 

由于tt可以是任何预定义的类型(指针或非指针),所以支持参数(tt * twoTimeable,如果我什至可以做到)似乎不是解决方案,或者我是否依赖函数的用户提供指针。如果我不必更改基础值,即使用值接收器,这不是问题,因为tt可以保存值或指向该值的指针

我总是接受答案。

3 个答案:

答案 0 :(得分:0)

  

是否存在一种方法,如果函数接受参数(ttTwoTimeable),则无论tt是否为类型指针,我都可以调用tt.result(),因为result()仅由指针接收器定义。

这似乎是一个主要的误解。如果tt是接口类型twoTimetable的变量,则一个result方法,可以调用此方法。但是tt的基础类型根本不是 matter 。接口类型完全封装了相关的基础类型。接口类型提供了一组方法,可以调用这些方法,而不能调用其他方法。

具体类型(例如,您的MyInt)对类型为twoInterfaces的变量的可分配性问题是一个不同 问题。如果您的具体类型(例如MyInt)碰巧具有由接口类型(此处为twoTimetables)定义的所有方法,则可以分配该类型,否则就可以分配。

问题“我的具体类型有什么方法”是第三个问题。这是唯一一个有点复杂的问题。在接收者T上定义的任何方法都是T的方法。对于指针类型* T来说,* T 上的方法和都是关于T count的方法。

答案 1 :(得分:-1)

  

Q1:为什么可以在值接收器方法上使用指针,但反之则不行呢?

因为语言规范说得很好:https://golang.org/ref/spec#Method_sets

  

相应指针类型* T的方法集是用接收者* T或T声明的所有方法的集合(也就是说,它还包含T的方法集)。

(规格可能如下所示:方便。)

对于其余的问题:我丝毫不知道你在问什么。 $rules['checkin'] = $request->checkin; $rules['checkout'] = $request->checkout; $rules['cancellation_policy'] = $request->cancellation_policy; $request->merge(['rules' => json_encode($rules)]); 的代码是完全可以的。您可以在实现do Something方法的任何类型的result上调用tt。此类型是否为指针类型无关紧要。您可以从此方法调用中返回两个result() (int, int),并且可以使用这些int进行任何操作。

(关于“指向接口的指针”部分:是的。在技术上可以做int。但是您从不需要这不需要。(从不。)(当然,这是一个谎言,但如果需要的话,它是如此的稀有和精致,以至于您真的不需要初学者,而一旦需要它,您就会知道如何使用它。)这里要记住一件事:永远不要做“指向接口的指针” )

答案 2 :(得分:-1)

  

对于m2和p2应该不是,因为现在没有使用* MyInt和* Pair的结果实现

不。您正在混淆不同的事物,并曲解了结果。

Go可让您在大多数情况下忽略指针取消引用。

type Pair struct {
    n1, n2 int
}
var pp *Pair = ...
fmt.Println(pp.n1)

看到最后一行? pp是指向Pair的指针,但无需编写(*pp).n1。 该取消引用是自动插入的(它是C语言中->运算符的自动变体)。

您的m2和p2只是包含指针的变量。如果需要,这些指针将被取消引用。与指针/值接收器或接口无关