Java程序员:包,函数和变量

Go熟悉的语法

由于它们在C编程语言中具有共同的遗产,因此Java开发人员应该可以完全理解Go (aka Golang)代码。 这是规范的“ Hello world”程序,您可以通过Go Playground网站上的浏览器执行和修改该程序:

package main

import "fmt"

func main() {
	fmt.Println("Hello world")
}

功能和控制结构以花括号开头和结尾。 函数参数用括号括起来,带有零参数的函数用空括号括起来。 严格来讲,Go语句与Java一样以分号结尾,尽管约定是让编译器隐式插入它们。 变量和函数的命名约定为“ camelCase”,而不是使用下划线(Python人们通常讨厌这样做!)。

其他Go基础知识也与Java相似。 Go代码被分组为“程序包”。 位于包main中的main()函数是Go程序的入口点……就像Java应用程序中的main方法一样:

package com.mycompany;

public class MyApplication {

   public static void main(String args[]) {
      System.out.println("Hello world");
   }

}

包,变量和函数

但是,当然存在差异。 比较以下扩展的Java代码:

公爵头

package com.mycompany;

import java.util.Date;

public class MyApplication {

	private Date currentTime;

	public static void main(String args[]) {
		MyApplication instance = new MyApplication();
		String message = instance.sayHello("world");
		System.out.println(message);
		System.out.println("The time is currently: " + instance.currentTime.toString());
	}

	public MyApplication() {
		currentTime = new Date();
	}

	private String sayHello(String listener) {
		return "Hello, " + listener;
	}

}

…对围棋同行:

地鼠头

package main

import (
	"fmt"
	"time"
)

var currentTime time.Time

func init() {
	currentTime = time.Now()
}

func main() {
	message := sayHello("world")
	fmt.Println(message)
	fmt.Println("The time is currently: " + currentTime.String())
}

func sayHello(listener string) string {
	return "Hello, " + listener
}

如您所见,Go变量和函数声明从Java开始以相反的顺序工作。 像所有Go函数一样,这里的sayHello声明以关键字func开头,而不是返回类型。 返回类型(在这种情况下为string)恰好在开口花括号之前。 函数参数也是如此。 参数声明不是String侦听器,而是侦听器字符串。

变量用关键字var声明,类型也跟在变量名之后。 但是,第15行显示了方便的速记符号。 当使用冒号等于运算符:=而不是普通的等号时,可以省略var关键字和变量类型。 编译器足够聪明,可以根据运算符右侧的内容推断出正确的类型。

范围和生命周期

由于变量消息是在main内部声明的,因此其范围仅限于该函数。 但是,currentTime在程序包级别声明,因此对于程序包中的所有函数都是可见的。 请注意,此处的变量和函数缺少访问级别修饰符。 Java使用关键字public,private等来控制从类或包外部的访问。 Go通过大写来做到这一点。 以小写字母开头的变量或函数类似于Java中的private。 如果currentTime变量已这样声明:

...
var CurrentTime time.Time
...

…然后,它将类似于Java的public,并且也可以从其他软件包中访问它。 可以在第16和17行上看到相同的约定,这些函数适用于函数。因为它以大写字母“ P”开头,所以可以在标准fmt包之外使用Println函数。

最后,请注意第10行上的init()函数。尽管main()是Go应用程序的主要入口点,但init()是一个特殊的(可选)函数,该函数会在其他所有函数之前自动被调用。 它通常用于初始化变量或其他设置和验证任务。 现在,您可以认为init()与Java构造函数大致相当,即使在Go语言中,静态方法与实例方法之间的区别并不十分适用。 关于Go与Java的面向对象进行比较的更多详细信息将在本系列的后面部分有关Go类型的文章中找到。

多种返回类型?!?

Java方法可以采用任意数量的输入参数,但始终返回的返回类型不得超过一个。 如果您需要一种方法来返回多个不同的信息,则可以创建一个自定义类型来保存多条信息……或者放弃并重构该方法以避免这种混乱。

Go函数的惊奇之处之一是,它们通常在一个调用中返回多个值! 考虑以下示例函数,该函数从字符串中修剪空格,并返回修剪后的字符串和在过程中删除的字符数:

package main

import (
	"fmt"
	"strings"
)

func main() {
	trimmedString, numberOfCharsRemoved := trimWithCount("This is a test   ")
	fmt.Printf("%d characters were trimmed from [%s]\n", numberOfCharsRemoved, trimmedString)
}

func trimWithCount(input string) (string, int) {
	trimmedString := strings.Trim(input, " ")
	numberOfCharsRemoved := len(input) - len(trimmedString)
	return trimmedString, numberOfCharsRemoved
}

您只需声明一个带有逗号分隔的返回类型列表的函数,就像声明一个逗号分隔的输入参数列表一样。 return语句必须以正确的顺序匹配这些类型。 调用函数时(如第9行所示),其结果应分配给以逗号分隔的变量列表,这些变量同样以正确的顺序排列。

正如我们将在本系列后面的内容中谈到的异常处理一样,Go广泛使用这种方法来报告错误。 如果函数中可能出现问题,通常返回结果和错误类型都是该函数。 调用者可以通过检查错误为nil(即null)来验证函数调用的干净成功:

...
number, err := strconv.Atoi(someNumericString)
if err != nil {
   // Could not parse this string variable as an integer
   log.Fatal(err)
}
...

延迟函数调用

通常,无论什么情况,您都有想要确保在给定块的末尾发生的逻辑。 Java通过try-catch-finally构造支持这一点。 即使在某些异常触发介于两者之间的catch块的情况下,final块内部的代码也应始终遵循其try块中的代码执行。

Java 7通过“资源尝试”机制增强了这一想法。 在try块开始时声明的诸如打开文件句柄或数据库连接之类的资源会自动关闭,即使您没有在finally块中手动进行关闭也是如此:

公爵头

...
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {

	// Do something with the file

} catch(Exception e) {
	log.error("An error occurred while processing the file: " + e);
} finally {
	log.debug("The 'finally' block was reached");
}
...

延迟的函数调用中,Go具有类似的机制。 当使用defer关键字调用一个函数时,则在从调用该函数的函数返回时执行该函数。

地鼠头

...
	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Could not open file")
		return
	}
	defer file.Close()

	// Do something with the file

	return
}
...

在这里,第7行对file.Close()的调用将始终在周围函数返回之前被调用,即使周围函数“ panics”(将在本系列后面的异常处理文章中介绍)。 任何功能都可以通过这种方式推迟。 需要注意的关键事项是:

  • 多个延迟的函数调用以LIFO顺序执行。 如果在第10行上的file.Close()调用之后安排了另一个延迟函数,则该函数将在file.Close() 之前调用。
  • 传递给延迟函数的任何参数都将在调度的函数处(而不是函数实际执行时)进行评估。

结论

Go中的语法,包,函数和变量与Java极为相似,但功能上却有所不同。 在Go for Java Programmers系列的下一篇文章中,我们将研究Go的控件结构。


翻译自: https://www.javacodegeeks.com/2014/03/go-for-java-programmers-packages-functions-and-variables.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值