),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
我们先把它分解成几个部分,分析哪些可以映射到 Go 中,哪些不能映射,并探索目前我们拥有的选项。
### 映射到 Go
一开始是相对比较简单的 —— 导入依赖项并启动 `main()` 函数。这里没有什么挑战性也不太有意思,只是语法上的变化:
package hello
import “github.com/flutter/flutter”
func main() {
app := NewApp()
flutter.Run(app)
}
唯一的不同的是不使用魔法的 `MyApp()` 函数,它是一个构造方法,也是一个特殊的函数,它隐藏在被称为 `MyApp` 的类中,我们只是调用一个显示定义的 `NewApp()` 函数 —— 它做了同样的事情,但它更易于阅读、理解和弄懂。
### Widget 类
在 Flutter 中,一切皆 widget(小组件)。在 Flutter 的 Dart 版本中,每个小组件都代表一个类,这个类扩展了 Flutter 中特殊的 Widget 类。
Go 中没有类,因此也没有类层次,因为 Go 的世界不是面向对象的,更不必说类层次了。对于只熟悉基于类的 OOP 的人来说,这可能是一个不太好的情况,但也不尽然。这个世界是一个巨大的相互关联的事物和关系图谱。它不是混沌的,可也不是完全的结构化,并且尝试将所有内容都放入类层次结构中可能会导致代码难以维护,到目前为止,世界上的大多数代码库都是这样子。
![OOP 的真相](https://user-gold-cdn.xitu.io/2019/7/7/16bca4d08789c000?imageView2/0/w/1280/h/960/ignore-error/1)
我喜欢 Go 的设计者们努力重新思考这个无处不在的基于 OOP 思维,并提出了与之不同的 OOP 概念,这与 OOP 的发明者 Alan Kay 所要表达的[真实意义]( )更接近,这不是偶然。
在 Go 中,我们用一个具体的类型 —— 一个结构体来表示这种抽象:
type MyApp struct {
// …
}
在一个 Flutter 的 Dart 版本中,`MyApp`必须继承于 `StatelessWidget` 类并覆盖它的 `build` 方法,这样做有两个作用:
1. 自动地给予 `MyApp` 一些 widget 属性/方法
2. 通过调用 `build`,允许 Flutter 在其构建/渲染管道中使用跟我们的组件
我不知道 Flutter 的内部原理,所以让我们不要怀疑我们是否能用 Go 实现它。为此,我们只有一个选择 —— [类型嵌入]( )
type MyApp struct {
flutter.Core
// …
}
这将增加 `flutter.Core` 中所有导出的属性和方法到我们的 `MyApp` 中。我将它称为 `Core` 而不是 `Widget`,因为嵌入的这种类型还不能使我们的 `MyApp` 称为一个 widget,而且,这是我在 [Vecty]( ) GopherJS 框架中看到的类似场景的选择。稍后我将简要的探讨 Flutter 和 Vecty 之间的相似之处。
第二部分 —— Flutter 引擎中的 `build` 方法 —— 当然应该简单的通过添加方法来实现,满足在 Go 版本的 Flutter 中定义的一些接口:
flutter.go 文件:
type Widget interface {
Build(ctx BuildContext) Widget
}
我们的 main.go 文件:
type MyApp struct {
flutter.Core
// …
}
// 构建渲染 MyApp 组件。实现 Widget 的接口
func (m *MyApp) Build(ctx flutter.BuildContext) flutter.Widget {
return flutter.MaterialApp()
}
我们可能会注意到这里和 Dart 版的 Flutter 有些不同:
* 代码更加冗长 —— `BuildContext`,`Widget` 和 `MaterialApp` 等方法前都明显地提到了 `flutter`。
* 代码更简洁 —— 没有 `extends Widget` 或者 `@override` 子句。
* Build 方法是大写开头的,因为在 Go 中它的意思是“公共”可见性。在 Dart 中,大写开头小写开头都可以,但是要使属性或方法“私有化”,名称需要使用下划线(\_)开头。
为了实现一个 Go 版的 Flutter `Widget`,现在我们需要嵌入 `flutter.Core` 并实现 `flutter.Widget` 接口。好了,非常清楚了,我们继续往下实现。
状态
--
在 Dart 版的 Flutter 中,这是我发现的第一个令人困惑的地方。Flutter 中有两种组件 —— `StatelessWidget` 和 `StatefulWidget`。嗯,对我来说,无状态组件只是一个没有状态的组件,所以,为什么这里要创建一个新的类呢?好吧,我也能接受。但是你不能仅仅以相同的方式扩展 `StatefulWidget`,你应该执行以下神奇的操作(安装了 Flutter 插件的 IDE 都可以做到,但这不是重点):
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
void _incrementCounter() { <