静态类型语言的生命周期方法

在去年,我已经成为一名移动开发人员和功能编程爱好者。

在每一个移动领域,都有组成了生命周期方法的应用程序。 以下将以Android和Kotlin为例,但iOS和Swift也一样。

在Android中,有Activity的生命周期方法,如onCreate() 。 您也可以定义一个函数onButtonClicked() ,它将完成名称所描述的内容。

为了这个问题的目的,我们假设在onCreate()中定义了一个变量,用在按钮点击处理函数onButtonClickedPrintMessageLength()通常情况下, onCreate()实际上是Activity的设置方法 )。

示例类看起来像这样:

 class ExampleActivity: Activity() { var savedStateMessage: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) savedStateMessage = "Hello World!" } fun onButtonClickedPrintMessageLength() { System.out.println(savedStateMessage?.length) } } 

注意savedStateMessage作为一个String?的声明String? (可空字符串)和使用?. (空安全呼叫)。 这些都是必须的,因为编译器不能保证在onButtonClickedPrintMessageLength()之前调用onCreate() onButtonClickedPrintMessageLength() 。 作为开发者, 我们知道onCreate总是被称为 * **

我的问题是如何告诉编译器有关这些方法的保证顺序,并消除空检查行为?

*我想有可能new我们的ExampleActivity并直接调用onButtonClickedPrintMessageLength() ,从而避开Android框架和生命周期方法,但编译器/ JVM在发生任何有趣的事情之前可能会遇到错误。

**首先调用onCreate的保证是由Android框架提供的,这是一个外在的真相来源,将来可能会有不同的功能。 看到所有的Android应用程序都基于这个真理来源,但我相信这是值得信赖的。

虽然这不会回答你的实际问题,但在Kotlin中你可以使用lateinit来告诉编译器,你将在稍后的时间点初始化一个var

lateinit var savedStateMessage: String

如果您在初始化之前尝试使用此变量,您将得到一个非常特定的UninitializedPropertyAccessException 。 这个特性在像JUnit这样的用例中非常有用,在这种用例中,你通常在@Before -annotated方法中初始化变量,在Android Activity ,你不能访问构造函数并在onCreate()初始化东西。

正如在另一个答案中提到的, lateinit可以作为一个选项来延迟初始化到保证生命周期中的一个更晚的点。 另一种方法是使用委托人:

 var savedStateMessage: String by Delegates.notNull() 

这相当于,如果在初始化之前访问该变量,它将报告一个错误。

在Swift中,您将使用隐式解包的Optional

 class Example: CustomStringConvertible { var savedStateMessage: String! // implicitly-unwrapped Optional<String> var description: String { return savedStateMessage } init() { savedStateMessage = "Hello World!" } } print(Example()) // => "Hello World!\n" 

通过使用操作员! 在这个例子的第二行的String结尾处,你有希望在变量被使用之前设置它。 这是在示例的init方法中完成的。 它仍然是一个Optional但代码可以把它当作一个String因为它会在每次使用之前自动解包。 您必须注意,可能访问该变量时永远不会将该变量设置nil ,否则可能会生成运行时异常。