英文:
Method vs Functions Usage golang
问题
我知道函数(func)和方法(method)之间的区别。但是我对以下用法感到困惑:
prod := Product{"title", "brand", "model"}
prod.Add()
或者:
prod := Product{"title", "brand", "model"}
products.Add(&prod) // products 是一个包(package)
英文:
I know differences between func and method. But I am confusing for usages between:
prod:=Product{"title","brand","model"}
prod.Add()
or:
prod:=Product{"title","brand","model"}
products.Add(&prod) // products is package
答案1
得分: 5
这是两种不同的情况,一种是属于Product
实例的方法,另一种是属于products
包的全局函数。
type Product struct {
Title string
Brand string
Model string
}
// 这个方法向Product的字段添加值
func (p *Product) Add(field, value string) {
switch field {
case "Title":
p.Title = value
case "Brand":
p.Brand = value
case "Model":
p.Model = value
}
}
上述代码提供了一种向Product
实例添加值的方法,例如:
product1 := &Product{}
product1.Add("Title", "first_title")
第二种情况是从products
包中公开的函数。在这种情况下,必须提供一个Product
实例(或指针)作为参数。
package products
func Add(p *Product, field, value string) {
// 与上述代码相同的switch-case
}
然后可以从任何其他包中使用Add
函数。
package main
import (
"path/to/products"
)
type Product struct {
// ...
}
func main() {
product1 := &Product{}
products.Add(product1, "Title", "first_title")
}
通常在您的场景中,首选第一种方法,因为它将管理属性的功能封装在自身中。
第二种情况可能被视为“类方法方法”(对于那些来自像Python或Java这样的面向对象编程语言的人),其中包类似于类,公开的函数类似于类方法,它们更通用,可以在实现相同接口的许多类型中使用,例如:
package products
// 其中p是Product接口
func Add(p Product, field, value string) {
// 与上述代码相同的switch-case
}
type Product interface {
someMethod()
}
然后在另一个包中:
package main
import (
"path/to/products"
)
type Car struct {
Title string
Brand string
Model string
}
type Ship struct {
// ...
}
type Airplane struct {
// ...
}
// 所有类型都实现了`Product`接口,可以在`products.Add`中使用
func (c *Car) someMethod() {}
func (s *Ship) someMethod() {}
func (a *Airplane) someMethod() {}
func main() {
plane := &Airplane{}
products.Add(plane, "Model", "Boeing-747")
}
英文:
These are two distinct cases, one which is a method belongs to Product
instance and one is a global function belongs to products
package.
type Product struct {
Title string
Brand string
Model string
}
// This method add value to a field in Product
func (p *Product) Add(field, value string) {
switch field {
case "Title":
p.Title = value
case "Brand":
p.Brand = value
case "Model":
p.Model = value
}
}
The above provide a method to add value to itself as an instance of Product
, i.e.
product1 := &Product{}
product1.Add("Title", "first_title")
The second case is a public function exposed from a product
package. In this case, an instance (or a pointer) of a Product
must be supplied as an argument.
package products
func Add(p *Product, field, value string) {
// Same switch-case as above
}
Add
function then can be used from any other package.
package main
import (
"path/to/products"
)
type Product struct {
// ...
}
func main() {
product1 := &Product{}
products.Add(product1, "Title", "first_title")
Normally in your scenario, the first approach is preferred since it encapsulates the functionality of managing its attributes to itself.
The second scenario might be seen as a "class method approach" (for those coming from OOP like Python or Java) where the package is similar to class and the exposed functions similar to class methods which are more generic and can be used across many types which implement the same interface, like so:
package products
// where p is a Product interface
func Add(p Product, field, value string) {
// Same switch-case as above
}
type Product interface {
someMethod()
}
And from another package:
package main
import (
"path/to/products"
)
type Car struct {
Title string
Brand string
Model string
}
type Ship struct {
// ...
}
type Airplane struct {
// ...
}
// All types implement `Product` and can be used in `products.Add`
func (c *Car) someMethod() {}
func (s *Ship) someMethod() {}
func (a *Airplane) someMethod() {}
func main() {
plane := &Airplane{}
products.Add(plane, "Model", "Boeing-747")
}
答案2
得分: 2
根据规范,这是预期的行为:
方法的类型是将接收者作为第一个参数的函数的类型。
请参考 https://golang.org/ref/spec#Method_declarations
因此,当你在 Product
上声明 Add
方法时,你得到一个接受指向 Product
的指针作为其第一个参数的函数。所以你最终得到的是:
func (p *Product) Add()
被翻译为
func Add(p *Product)
所以你的两个调用都是有效的,并且最终执行相同的操作。
英文:
This is expected as per the spec:
> The type of a method is the type of a function with the receiver as first argument.
See https://golang.org/ref/spec#Method_declarations
So when you declare the Add
method on Product
, you get a function that accepts a pointer to a Product
as its first argument. So you end up with
func (p *Product) Add()
being translated to
func Add(p *Product)
So both your calls are valid and end up doing the same
答案3
得分: 0
扩展了@Danilo的精彩答案:
package main
import "fmt"
type T struct {
i int
}
func (t *T) F() {
t = &T{1}
fmt.Println(t.i)
}
func F(t *T) {
fmt.Println(t.i)
}
func main() {
t := T{2}
(&t).F()
F(&t)
}
方法func (t *T) F()
的类型是函数func F(t *T)
的类型,其中接收者(t *T)
作为第一个参数。
英文:
Extending the fantastic answer by @Danilo:
package main
import "fmt"
type T struct {
i int
}
func (t *T) F() {
t = &T{1}
fmt.Println(t.i)
}
func F(t *T) {
fmt.Println(t.i)
}
func main() {
t := T{2}
(&t).F()
F(&t)
}
The type of the method func (t *T) F()
is the type of the function func F(t *T)
with the receiver (t *T)
as first argument.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论