Java与Go的一个区别 2022-07-12 11:07 Java与Go的一个区别:Java通常以类为单位对外提供服务,而Go以包为单位对外提供服务。 ### Java中 在Java中有一个工具类,包路径是com.example.demo.Utils,类名为WebUtil: ```java package com.example.demo.Utils; import javax.servlet.http.HttpServletRequest; /** * @author: HanXu * on 2020/1/17 * Class description: web相关工具 */ public class WebUtil { /** * 获取ip 获取访问者的真实ip * @param request * @return */ public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } } ``` 如果我要在本项目的其他地方使用它,则我应该这样用:`String ip = WebUtil.getIp(request);` 使用类名.方法名,这样可以很明显的知道使用的方法是哪个类下的;由于类名也代表了文件名,所以也就很明确的知道了使用的是WebUtil.java这个文件。 其实全称是这样的:`String ip = com.example.demo.Utils.WebUtil.getIp(request);` 因为包路径被我们import显示的写出来了:`import com.example.demo.Utils.WebUtil;`,所以使用时可以不写包路径直接写`WebUtil`。 ### Go中 而在Go中,假如有一个utils包,包下有两个文件: Time.go: ```go package utils import ( "time" ) const ( Day = time.Hour * 24 ) func GetStartAtEndAt(now time.Time, loc *time.Location, duration time.Duration) (startAt time.Time, endAt time.Time) { now = now.In(loc) startAt = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), time.UTC) startAt = startAt.Truncate(duration) startAt = time.Date(startAt.Year(), startAt.Month(), startAt.Day(), startAt.Hour(), startAt.Minute(), startAt.Second(), startAt.Nanosecond(), loc) endAt = startAt.Add(duration) return startAt.In(time.UTC), endAt.In(time.UTC) } ``` JsonMap.go: ```go package utils import ( "encoding/json" "fmt" ) func MapToJson(m map[string]interface{}) (string, error) { jsonData, err := json.Marshal(m) if err != nil { fmt.Println("parse json error:", err) return "", err } return string(jsonData), nil } ``` 若我想在本项目的其他地方使用MapToJson,则需要这样写:`json, err := utils.MapToJson(m)`。 若我想使用GetStartAtEndAt,则需要这样写:`startAt, endAt := utils.GetStartAtEndAt(time.Now(), time.UTC, utils.Day)`。都需要引入包`import "TestGo/utils"`。 这样的写法并不能直接知道使用的函数是在哪个文件中,所以Go中对函数的引用隐藏了文件的概念,你只能知道你使用的是哪个包里的东西。 只有你点进方法里,才知道,噢,原来`MapToJson`和`GetStartAtEndAt`不是在一个叫做`utils`的文件中啊。他们只是在utils包下,即使你点进来,也要再看一眼才能知道这两个方法分别在什么文件下。 ### 相关问题 或许你想,既然只知道包和函数,那就干脆只使用包和函数喽。 于是可能萌生出这样的想法:一个专门用作操作db的包下有许多文件,每个文件对应操作数据库的一张表,想象之中应该是这样的: - model 包,对外提供数据库层面的CRUD操作 - Company 文件,对外提供Company相关的操作,通常Company对应一张db表 - User 文件,对外提供User相关的操作,通常User也对应一张db表 Company.go: ```go type Company struct { Name string //... } //插入一条Company记录 func Insert(p Company) { } ``` User.go: ```go type User struct { Name string //... } //插入一条User记录 func Insert(c User) { } ``` 但是真的实际行动起来,却发现了错误,无法编译通过:同一个包下出现了两个同名的public方法Insert。 啊,对哦,以包为单位对外提供服务时,一个包内的public方法都不能重名啊。那怎么办呢?那不成要改为`InsertCompany`、`InsertUser`方法?这也太难看了吧。 最终发现,想要使用类似company.Insert、user.Insert这样的方法,解决方法只有一种:强行给他们用上面向对象。这就将每个文件抽象成一个「结构体包」,这个「包」并不是真实的包,只是说他和其他文件是隔离开的。 ```go type Company struct { Name string //... } func (c Company)Insert() { } ``` ```go type User struct { Name string //... } func (u User) Insert() { } ``` --END--
发表评论