javaer to go之基础
2016-03-29 17:46
483 查看
1、开始
我是一个javaer,最近空闲时间在学习golang。度娘后,安装好Go环境和LiteIDE后,一开始我也没从基础开始看,而是想把现有的java项目改成是golang版本的。
原项目内容:
socket模块接收下位机的数据
对协议数据进行解析
把协议数据解析后存进数据库
web子项目
golang相比java,有很多很方便的特性。特别是并发与网络方面更是golang的卖点。所以我就直接找了个socket的例子开始模拟着实现项目的socket模块
2、第一个程序
server.go :package socket import ( "fmt" "net" "strings" ) func StartServer() { service := ":3338" tcpAddr, err := net.ResolveTCPAddr("tcp4", service) checkError(err) listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err) for { conn, err := listener.Accept() if err != nil { continue } fmt.Println("新连接:", conn.RemoteAddr().String()) go handleConn(conn) } } func handleConn(conn net.Conn) { for { buffer := make([]byte, 1024) length, err := conn.Read(buffer) if err != nil { conn.Close() } if length > 12 { data := buffer[:length] switch data[11] & 0xff { case 0x80: //桌子 fmt.Println("桌子") case 0x90: //椅子 case 0xA0: //台灯 default: //其它 } //写数据 // conn.Write(data) } } } func isProtocol(data []byte) bool { if (data[0]&0xff) == 0xC0 && (data[len(data)-1]&0xff) == 0xC1 { return true } return false } func checkError(err error) { if err != nil { fmt.Println(err.Error()) } }
因为是第一篇笔记,也简单地说一下golang的基础语法。
对于一个javaer来说,或者一个有计算机语言基础的朋友来说,golang的语法看起来不会太困难。
3、包路径
像java一样,一开始我们为程序声明一个包路径package socket
和java不一样的是,golang的包不是层叠式的。所以为了方便识别我们也可以为我们所有的项目放到一个父包下。
类似与java,我这里使用了一个letus.xyz的命名作为父包(文件夹)。这样其它的程序就能比较方便地找到server.go程序来调用。
如果想要构建一个程序,则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。
属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包。
如果对一个包进行更改或重新编译,所有引用了这个包的客户端程序都必须全部重新编译。
4、包与库的导入
import ( "fmt" "net" "strings" )
和java相比,golang使用的这种方式进行导包和库看起来优雅多了。
当然,你也可以像java一样,一个一个地import
import "fmt" import "net" import "strings"
注意事项:
如果你导入了一个包却没有使用它,则会在构建程序时引发错误,如 imported and not used: os,这正是遵循了 Go 的格言:“没有不必要的代码!“。
当你导入多个包时,导入的顺序会按照字母排序。
如果包名不是以 . 或 / 开头,如 “fmt” 或者 “container/list”,则 Go 会在全局文件进行查找;如果包名以 ./ 开头,则 Go 会在相对目录中查找;如果包名以 / 开头(在 Windows 下也可以这样使用),则会在系统的绝对路径中查找。
导入包即等同于包含了这个包的所有的代码对象。
除了符号 _,包中所有代码对象的标识符必须是唯一的,以避免名称冲突。但是相同的标识符可以在不同的包中使用,因为可以使用包名来区分它们。
5、 函数
导入包和库之后,就是我们的程序主体了。当然,我们写程序的时候肯定是package之后就直接写程序主体,而包与库是到用到这个包内容的时候再导。golang和c一样,是面向过程的函数式编程,而不是java那样的面向对象。
func StartServer() { } func isProtocol(data []byte) bool { return false } func checkError(err error) { }
可见性规则:
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。
函数的基本结构:
func functionName(parameter_list) (return_value_list) { … }
其中:
参数:parameter_list 的形式为 (param1 type1, param2 type2, …)
返回类型return_value_list 的形式为 (ret1 type1, ret2 type2, …)
golang的方法比java有意思的是它允许返回多个值。而它的参数表示形式与java也不一样,名字是放在类型的前面。
6、变量
service := ":3338"
:=是简短声明语法 ,表示声明并赋值。
或者你也可以用var来声明:
var service = ":3338"
或
var service string service = ":3338"
简短声明法看起来更加优雅些。
7、常量
const ( Unknown = 0 Female = 1 Male = 2 )
我们第一个程序没用到常量。常量是通过const来定义的。
常量的定义格式:
const identifier [type] = value
8、基本数据类型
int,Runes(注:Rune 是int 的别名)int8 ,int16 ,int32 ,int64
byte ,uint8 ,uint16 ,uint32 ,uint64 (注:byte是uint8 的别名)
float32 ,float64 (没有float 类型)
bool
string
complex128,complex64
9、main函数
package main import ( "letus.xyz/socket" ) func main() { socket.StartServer() }
这里我们通过绝对路径letus.xyz主包找到socket包来调用程序。当然我们也可以相对目录导入。很明显,相对路径的方式不利于包的复用。
所以个人建议使用绝对路径来导包,毕竟思想上和java相似。
import ( "../socket" )
10、其它
golang的运算符与控制结构语句的使用基本和java的一样,但值得一提的是,golang的switch语法支持字符串的匹配。这是作为一个javaer经常想java也提供的一个特性。switch field.Type().String() { case "time.Time": v, _ := time.Parse("2006-01-02 15:04:05", s) field.Set(reflect.ValueOf(v)) }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Linux socket 初步
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序