Baru-baru ini, saya menemukan Flutter - kerangka kerja baru dari Google untuk mengembangkan aplikasi mobile lintas platform - dan bahkan memiliki kesempatan untuk menunjukkan dasar-dasar Flutter kepada seseorang yang belum pernah diprogram sebelumnya. Flutter sendiri ditulis di Dart - bahasa yang lahir di browser Chrome dan lolos ke dunia konsol - dan itu membuat saya berpikir "hmm, tapi Flutter bisa ditulis dalam Go!".
Kenapa tidak Baik Go dan Dart dibuat oleh Google, keduanya dikompilasi dengan bahasa yang dikompilasi - membalikkan beberapa peristiwa dengan sedikit berbeda, Go akan menjadi kandidat yang sangat baik untuk mengimplementasikan proyek skala besar seperti Flutter. Seseorang akan mengatakan - tidak ada kelas, generik, dan pengecualian di Go, jadi tidak cocok.
Jadi mari kita berpura-pura bahwa Flutter sudah ditulis di Go. Bagaimana kode akan terlihat dan secara umum, apakah akan berfungsi?

Apa yang salah dengan Dart?
Saya telah mengikuti bahasa ini sejak awal sebagai alternatif untuk JavaScript di browser. Dart dibangun ke dalam browser Chrome untuk beberapa waktu dan harapannya adalah itu akan menggantikan JS. Sangat menyedihkan membaca pada Maret 2015 bahwa dukungan Dart telah dihapus dari Chrome .
Dart itu sendiri luar biasa! Yah, pada dasarnya, setelah JavaScript, bahasa apa pun hebat, tetapi setelah, katakan, Go, Dart tidak begitu indah. tapi cukup baik. Ini memiliki semua fitur yang mungkin dan tidak dapat dibayangkan - kelas, generik, pengecualian, futures, async-waiting, loop acara, JIT / AOT, pengumpul sampah, kelebihan fungsi - nama fitur yang dikenal dari teori bahasa pemrograman dan di Dart akan dengan proporsi tinggi probabilitas. Dart memiliki sintaks khusus untuk hampir semua chip - sintaks khusus untuk getter / setter, sintaks khusus untuk konstruktor disingkat, sintaks khusus untuk sintaks khusus dan banyak lagi.
Ini membuat Dart langsung dari pandangan pertama menjadi akrab bagi orang-orang yang telah memprogram dalam bahasa pemrograman apa pun sebelumnya, dan itu hebat. Tetapi mencoba menjelaskan semua fitur istimewa yang berlimpah ini dalam contoh "Halo, dunia" yang sederhana, saya menemukan bahwa, sebaliknya, itu mempersulit pengembangan.
- semua "khusus" fitur bahasa membingungkan - "metode khusus yang disebut konstruktor", "sintaks khusus untuk inisialisasi otomatis", "sintaks khusus untuk parameter bernama", dll.
- semuanya "tersembunyi" membingungkan - "dari impor apa fungsi ini? tersembunyi, melihat kode yang tidak dapat Anda temukan", "mengapa ada konstruktor di kelas ini, tetapi tidak di kelas ini? ada di sana, tetapi disembunyikan" dan seterusnya
- semuanya "ambigu" bingung - "jadi di sini untuk membuat parameter fungsi dengan atau tanpa nama?", "haruskah konst atau final?", "di sini menggunakan sintaks fungsi normal atau '' disingkat dengan panah ''", dll.
Pada prinsipnya, trinitas ini - "khusus", "tersembunyi" dan "ambigu" - tidak buruk menangkap esensi dari apa yang orang sebut "sihir" dalam bahasa pemrograman. Ini adalah fitur yang dibuat untuk menyederhanakan penulisan kode, tetapi pada kenyataannya menyulitkan pembacaan dan pemahamannya.
Dan inilah tepatnya area di mana Go mengambil posisi yang secara fundamental berbeda dari bahasa lain, dan dengan kuat memegang pertahanan. Go adalah bahasa yang nyaris tanpa sihir - jumlah "tersembunyi", "istimewa" dan "ambigu" di dalamnya diminimalkan. Tapi Go memiliki kekurangannya.
Apa yang salah dengan Go?
Karena kita berbicara tentang Flutter, yang merupakan kerangka kerja UI, mari kita pertimbangkan Go sebagai alat untuk menggambarkan dan bekerja dengan UI. Secara umum, kerangka kerja UI adalah tantangan yang luar biasa dan hampir selalu membutuhkan solusi khusus. Salah satu pendekatan yang paling sering di UI adalah penciptaan DSL - bahasa khusus domain - diimplementasikan dalam bentuk perpustakaan atau kerangka kerja yang dirancang khusus untuk kebutuhan UI. Dan paling sering Anda bisa mendengar pendapat bahwa Go secara objektif adalah bahasa yang buruk untuk DSL.
Intinya, DSL berarti menciptakan bahasa baru - istilah dan kata kerja - tempat pengembang dapat beroperasi. Kode di atasnya harus dengan jelas menggambarkan fitur utama dari antarmuka grafis dan komponennya, cukup fleksibel untuk memberikan kebebasan pada imajinasi perancang, dan pada saat yang sama cukup kaku untuk membatasinya sesuai dengan aturan tertentu. Misalnya, Anda harus dapat menempatkan tombol di beberapa wadah, dan meletakkan ikon di tempat yang tepat di tombol ini, tetapi kompiler harus mengembalikan kesalahan jika Anda mencoba memasukkan tombol, misalnya, teks.
Plus, bahasa untuk menggambarkan UI sering bersifat deklaratif - memberikan kesempatan untuk menggambarkan antarmuka dalam bentuk "apa yang ingin saya lihat", dan biarkan kerangka itu sendiri mengerti dari kode mana dan bagaimana menjalankannya.
Beberapa bahasa pada awalnya dikembangkan dengan tugas-tugas seperti itu yang terlihat, tetapi tidak Go. Tampaknya menulis Flutter on Go akan menjadi tugas lain!
Oda Flutter
Jika Anda tidak terbiasa dengan Flutter, maka saya sangat merekomendasikan menghabiskan akhir pekan berikutnya menonton video pendidikan atau membaca tutorial, yang jumlahnya banyak. Karena Flutter, tanpa ragu, membalikkan aturan permainan dalam pengembangan aplikasi seluler. Dan, sangat mungkin, tidak hanya ponsel - sudah ada penyaji (dalam hal Flutter, embedders) untuk meluncurkan aplikasi Flutter sebagai aplikasi dekstop asli , dan sebagai aplikasi web .
Mudah dipelajari, logis, dilengkapi dengan perpustakaan besar widget indah tentang Desain Material (dan tidak hanya), ia memiliki komunitas yang hebat dan besar dan penyetelan yang sangat baik (jika Anda suka kemudahan bekerja dengan go build/run/test
di Go, maka di Flutter Anda akan mendapatkan pengalaman serupa).
Setahun yang lalu, saya perlu menulis aplikasi seluler kecil (untuk iOS dan Android, tentu saja), dan saya menyadari bahwa kompleksitas pengembangan aplikasi berkualitas tinggi untuk kedua platform terlalu besar (aplikasi itu bukan tugas utama) - Saya harus memasang iklan dan membayar uang untuk itu. Bahkan, menulis aplikasi yang tidak rumit, tetapi berkualitas tinggi dan bekerja pada semua perangkat adalah tugas yang mustahil bahkan untuk orang dengan pengalaman pemrograman hampir 20 tahun. Dan itu selalu omong kosong bagiku.
Dengan Flutter, saya menulis ulang aplikasi ini dalam jam 3 sore, sambil mempelajari kerangka itu sendiri dari awal. Jika seseorang mengatakan kepada saya bahwa ini mungkin sedikit lebih awal, saya tidak akan mempercayainya.
Terakhir kali saya melihat peningkatan produktivitas yang serupa dengan penemuan teknologi baru adalah 5 tahun yang lalu ketika saya menemukan Go. Momen itu mengubah hidup saya.
Jadi saya sarankan mulai belajar Flutter dan tutorial ini sangat bagus .
"Halo, Dunia" di Flutter
Saat Anda membuat aplikasi baru melalui flutter create
, Anda akan mendapatkan program seperti itu dengan judul, teks, penghitung, dan tombol yang menambah penghitung.

Saya pikir ini adalah contoh yang bagus. untuk menulisnya di Flutter imajiner kami on Go. Ini memiliki hampir semua konsep dasar kerangka kerja di mana Anda dapat menguji ide tersebut. Mari kita lihat kodenya (ini satu file):
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
Mari kita menganalisis kode di bagian-bagian, menganalisis apa dan bagaimana cocok di Go, dan lihat berbagai opsi yang kita miliki.
Kami menerjemahkan kode di mana pun
Awal akan sederhana dan mudah - mengimpor dependensi dan meluncurkan fungsi main()
. Tidak ada yang rumit atau menarik di sini, perubahannya hampir sintaksis:
package hello import "github.com/flutter/flutter" func main() { app := NewApp() flutter.Run(app) }
Satu-satunya perbedaan adalah bahwa alih-alih meluncurkan MyApp()
- fungsi yang merupakan konstruktor, yang merupakan fungsi khusus yang disembunyikan di dalam kelas yang disebut MyApp - kita cukup memanggil fungsi NewApp()
eksplisit dan tidak tersembunyi NewApp()
. Dia melakukan hal yang sama, tetapi jauh lebih jelas untuk menjelaskan dan memahami apa itu, bagaimana itu dimulai dan bagaimana cara kerjanya.
Kelas widget
Di Flutter, semuanya terdiri dari widget. Dalam Flutter versi Dart, setiap widget diimplementasikan sebagai kelas yang mewarisi kelas khusus untuk widget dari Flutter.
Tidak ada kelas di Go, dan karenanya tidak ada hierarki kelas, karena dunia tidak berorientasi objek, dan bahkan lebih tidak hirarkis. Untuk programmer yang hanya mengenal model OOP yang berorientasi kelas, ini mungkin sebuah wahyu, tetapi sebenarnya tidak. Dunia adalah grafik konsep, proses, dan interaksi terjalin raksasa. Itu tidak terstruktur sempurna, tetapi tidak kacau, dan mencoba untuk memerasnya ke dalam hierarki kelas adalah cara yang paling dapat diandalkan untuk membuat basis kode tidak dapat dibaca dan kikuk - persis seperti apa basis kode yang paling untuk saat ini.

Saya sangat menghargai Go karena penciptanya mengambil kesulitan untuk memikirkan kembali konsep kelas yang ada di mana-mana ini dan menerapkannya dalam konsep OOP yang jauh lebih sederhana dan lebih kuat, yang, bukannya kebetulan, ternyata lebih dekat dengan apa yang ada dalam pikiran pencipta OOP, Alan Kay, dalam pikiran .
Di Go, kami mewakili abstraksi apa pun dalam bentuk tipe - struktur tertentu:
type MyApp struct {
Dalam Flutter versi Dart, MyApp
harus mewarisi StatelessWidget
dan mengganti metode build
. Ini diperlukan untuk menyelesaikan dua masalah:
- berikan widget kami (
MyApp
) beberapa properti / metode khusus - aktifkan Flutter untuk memanggil kode kami dalam proses build / render
Saya tidak tahu bagian dalam Flutter, jadi katakanlah item nomor 1 tidak dipertanyakan, dan kita hanya perlu melakukannya. Go memiliki solusi yang unik dan jelas untuk ini: jenis penyematan :
type MyApp struct { flutter.Core
Kode ini akan menambahkan semua properti dan metode flutter.Core
ke tipe MyApp
kami. Saya menyebutnya Core
bukan Widget
, karena, pertama, tipe embedding belum menjadikan MyApp
kami MyApp
widget, dan kedua, nama ini sangat baik digunakan dalam kerangka kerja GopherJS Vecty (sesuatu seperti React, only for Go). Saya akan menyentuh pada topik kesamaan antara Vecty dan Flutter sedikit kemudian.
Poin kedua - implementasi metode build()
, yang akan dapat menggunakan mesin Flutter - juga dipecahkan secara sederhana dan jelas di Go. Kita hanya perlu menambahkan metode dengan tanda tangan tertentu yang memenuhi antarmuka tertentu yang didefinisikan di suatu tempat di perpustakaan Flutter fiksi kami di Go:
flutter.go:
type Widget interface { Build(ctx BuildContext) Widget }
Dan sekarang main.go kami:
type MyApp struct { flutter.Core
Kami dapat melihat beberapa perbedaan di sini:
- kode ini agak lebih verbose -
BuildContext
, Widget
dan MaterialApp
menunjuk ke impor BuildContext
di depannya. - kode ini sedikit tidak berdasar - tidak ada kata seperti
extends Widget
atau @override
- Metode
Build()
dimulai dengan huruf kapital, karena itu berarti "publisitas" dari metode di Go. Di Dart, publisitas ditentukan oleh apakah nama dimulai dengan garis bawah (_) atau tidak.
Jadi, untuk membuat widget di Flutter on Go, kita perlu menyematkan flutter.Core
ketik dan mengimplementasikan antarmuka flutter.Widget
. Kami menemukan jawabannya, menggali lebih jauh.
Ketentuan
Ini adalah salah satu hal yang benar-benar membingungkan saya di Flutter. Ada dua kelas yang berbeda - StatelessWidget
dan StatefulWidget
. Bagi saya, "widget stateless" adalah widget yang sama, hanya tanpa, hmm, data, status - mengapa datang dengan kelas baru? Tapi oke, saya bisa hidup dengannya.
Tetapi lebih jauh - lebih lanjut, Anda tidak bisa hanya mewarisi kelas lain ( StatefulWidget
), tetapi Anda harus menulis keajaiban seperti itu (IDE akan melakukannya untuk Anda, tetapi bukan intinya):
class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold() } }
Hmm, mari kita lihat apa yang terjadi di sini.
Pada dasarnya, tugasnya adalah ini: tambahkan status ke widget - penghitung, dalam kasus kami - dan beri tahu mesin Flutter saat kami mengubah status untuk menggambar ulang widget. Ini adalah kompleksitas masalah yang sebenarnya (kompleksitas esensial dalam istilah Brooks).
Yang lainnya adalah kompleksitas yang tidak disengaja. Flutter on Dart hadir dengan kelas State
baru yang menggunakan obat generik dan menggunakan widget sebagai parameter tipe. Selanjutnya, kelas _MyHomePageState
, yang mewarisi keadaan State MyApp
... oke, Anda masih bisa mencernanya. Tapi mengapa metode build()
didefinisikan oleh kelas State, dan bukan kelas widgetnya? Brrr ....
Jawaban untuk pertanyaan ini ada di Flutter FAQ dan jawaban singkatnya dipertimbangkan secara cukup rinci di sini - untuk menghindari kelas bug tertentu ketika mewarisi StatefulWidget
. Dengan kata lain, ini adalah solusi untuk menyelesaikan masalah desain OOP berorientasi kelas. Cantik.
Bagaimana kita melakukan ini di Go?
Pertama, saya pribadi secara pribadi lebih suka untuk tidak membuat entitas terpisah untuk "negara" - State
. Bagaimanapun, kita sudah memiliki keadaan di setiap jenis tertentu - ini hanya bidang struktur. Bahasa telah memberi kita esensi ini, sehingga untuk berbicara. Membuat entitas lain yang serupa hanya akan membingungkan programmer.
Tantangannya, tentu saja, adalah memberi Flutter kemampuan untuk merespons perubahan keadaan (bagaimanapun juga, inilah inti dari pemrograman reaktif). Dan jika kita dapat "meminta" pengembang untuk menggunakan fungsi khusus ( setState()
), maka dengan cara yang sama kita dapat meminta untuk menggunakan fungsi khusus untuk memberi tahu mesin kapan harus digambar ulang dan kapan tidak. Pada akhirnya, tidak semua perubahan negara memerlukan penggambaran ulang, dan di sini kita akan memiliki kontrol lebih besar:
type MyHomePage struct { flutter.Core counter int }
Anda dapat bermain NeedsUpdate()
main dengan opsi penamaan yang berbeda - Saya suka NeedsUpdate()
karena keterusterangannya dan fakta bahwa ini adalah properti widget (diperoleh dari flutter.Core
), tetapi metode global flutter.Rerender()
juga terlihat bagus. Benar, itu memberikan perasaan yang salah bahwa widget akan segera digambar ulang dengan segera, tetapi tidak demikian - itu akan digambar ulang pada pembaruan bingkai berikutnya, dan frekuensi pemanggilan metode bisa jauh lebih tinggi daripada frekuensi render - tetapi mesin Flutter kami harus sudah menangani hal ini.
Tapi idenya adalah kita baru saja memecahkan masalah yang diperlukan tanpa menambahkan:
- tipe baru
- obat generik
- aturan khusus untuk kondisi membaca / menulis
- metode khusus baru yang ditimpa
Plus, API jauh lebih jelas dan lebih mudah dipahami - cukup tambahkan penghitung (seperti yang Anda lakukan dalam program lain) dan minta Flutter untuk menggambar ulang widget. Ini hanya apa yang tidak terlalu jelas jika kita hanya memanggil setState
- yang bukan hanya fungsi khusus untuk pengaturan keadaan, itu adalah fungsi yang mengembalikan fungsi (wtf?) Di mana kita sudah melakukan sesuatu dengan keadaan. Sekali lagi, sihir tersembunyi dalam bahasa dan kerangka membuatnya sangat sulit untuk memahami dan membaca kode.
Dalam kasus kami, kami memecahkan masalah yang sama, kode lebih sederhana dan dua kali lebih pendek.
Sebutkan widget di widget lain
Sebagai kelanjutan logis dari topik, mari kita lihat bagaimana "widget negara" digunakan dalam widget lain di Flutter:
@override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: MyHomePage(title: 'Flutter Demo Home Page'), ); }
MyHomePage
sini adalah "widget negara" (memiliki penghitung), dan kami membuatnya dengan memanggil konstruktor MyHomePage()
selama pembuatan ... Tunggu, apa?
build()
dipanggil untuk menggambar ulang widget, sangat mungkin berkali-kali per detik. Mengapa kita harus membuat widget, terutama dengan status, setiap kali selama rendering? Itu tidak masuk akal.
Ternyata Flutter menggunakan pemisahan antara Widget
dan State
untuk menyembunyikan inisialisasi / manajemen negara ini dari programmer (lebih banyak hal tersembunyi, lebih banyak!). Itu membuat widget baru setiap kali, tetapi negara, jika sudah dibuat, secara otomatis ditemukan dan dilampirkan ke widget. Keajaiban ini terjadi tanpa terlihat dan saya tidak tahu cara kerjanya - Anda perlu membaca kode.
Saya menganggap itu sebagai kejahatan nyata dalam pemrograman untuk bersembunyi dan bersembunyi dari programmer sebanyak mungkin, membenarkannya dengan ergonomi. Saya yakin bahwa programmer statistik rata-rata tidak akan membaca kode Flutter untuk memahami bagaimana sihir ini bekerja, dan tidak mungkin untuk memahami bagaimana dan apa yang saling berhubungan.
Untuk versi Go, saya pasti tidak ingin sihir yang tersembunyi seperti itu, dan akan lebih memilih inisialisasi yang eksplisit dan terlihat, bahkan jika itu berarti kode yang sedikit lebih tidak berdasar. Pendekatan Flutter terhadap Dart juga dapat diimplementasikan, tetapi saya suka Go karena meminimalkan sihir, dan saya ingin melihat filosofi yang sama dalam kerangka kerja. Karenanya, saya akan menulis kode untuk widget dengan status di pohon widget seperti ini:
Kode ini kehilangan versi Dart karena jika saya ingin menghapus homePage
dari pohon widget dan menggantinya dengan yang lain, maka saya harus menghapusnya di tiga tempat, bukan satu. Tetapi sebagai gantinya, kami mendapatkan gambaran lengkap tentang apa, di mana dan bagaimana hal itu terjadi, di mana memori dialokasikan, siapa yang memanggil siapa, dan seterusnya - kode di telapak tangan Anda jelas dan mudah dibaca.
Ngomong-ngomong, Flutter juga memiliki yang namanya StatefulBuilder , yang menambahkan lebih banyak keajaiban dan memungkinkan Anda untuk membuat widget dengan status aktif.
DSL
Sekarang mari kita ambil bagian yang menyenangkan. Bagaimana kami akan mewakili pohon widget on Go? Kami ingin itu terlihat ringkas, bersih, mudah untuk refactor dan berubah, menggambarkan hubungan spasial antara widget (widget yang secara visual dekat, harus dekat dan dalam deskripsi), dan pada saat yang sama cukup fleksibel untuk menggambarkan secara sewenang-wenang. kode seperti penangan acara.
Tampaknya bagi saya bahwa opsi pada Dart cukup indah dan fasih:
return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('You have pushed the button this many times:'), Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), );
Setiap widget memiliki konstruktor yang menerima parameter opsional, dan apa yang membuat catatan sangat bagus di sini adalah parameter bernama dari fungsi .
Parameter yang Dinamai
Jika Anda tidak terbiasa dengan istilah ini, maka dalam banyak bahasa parameter fungsi disebut "posisional", karena posisi mereka penting bagi fungsi:
Foo(arg1, arg2, arg3)
, dan dalam hal parameter bernama, semuanya diputuskan dengan namanya dalam panggilan:
Foo(name: arg1, description: arg2, size: arg3)
Ini menambahkan teks, tetapi menyimpan klik dan bergerak di sekitar kode, dalam upaya untuk memahami apa arti parameter.
Dalam kasus pohon widget, mereka memainkan peran kunci dalam keterbacaan. Bandingkan kode yang sama seperti di atas, tetapi tanpa parameter bernama:
return Scaffold( AppBar( Text(widget.title), ), Center( Column( MainAxisAlignment.center, <Widget>[ Text('You have pushed the button this many times:'), Text( '$_counter', Theme.of(context).textTheme.display1, ), ], ), ), FloatingActionButton( _incrementCounter, 'Increment', Icon(Icons.add), ), );
Bukan itu. benar kan Tidak hanya lebih sulit untuk dipahami (Anda perlu mengingat apa arti setiap parameter dan jenisnya, dan ini adalah beban kognitif yang signifikan), tetapi juga tidak memberi kami kebebasan dalam memilih parameter mana yang ingin kami transfer. Misalnya, Anda mungkin tidak ingin FloatingActionButton
untuk aplikasi Material Anda, jadi Anda tidak menentukannya dalam parameter. Tanpa parameter bernama, kita harus memaksa semua widget yang mungkin untuk ditentukan, atau menggunakan sihir dengan refleksi untuk mencari tahu widget mana yang ditransfer.
Dan karena tidak ada kelebihan fungsi dan parameter bernama di Go, ini tidak akan menjadi tugas yang mudah untuk Go.
Buka pohon widget
Versi 1
Mari kita melihat lebih dekat objek Scaffold , yang merupakan pembungkus yang nyaman untuk aplikasi mobile. Ini memiliki beberapa properti - appBar, drawe, home, bottomNavigationBar, floatingActionBar - dan ini semua adalah widget. Saat membuat pohon widget, kita sebenarnya harus menginisialisasi objek ini, lalu meneruskannya dengan properti widget yang disebutkan di atas. Nah, ini tidak terlalu berbeda dengan kreasi dan inisialisasi objek yang biasa.
Mari kita coba pendekatan dahi:
return flutter.NewScaffold( flutter.NewAppBar( flutter.Text("Flutter Go app", nil), ), nil, nil, flutter.NewCenter( flutter.NewColumn( flutter.MainAxisCenterAlignment, nil, []flutter.Widget{ flutter.Text("You have pushed the button this many times:", nil), flutter.Text(fmt.Sprintf("%d", m.counter), ctx.Theme.textTheme.display1), }, ), ), flutter.FloatingActionButton( flutter.NewIcon(icons.Add), "Increment", m.onPressed, nil, nil, ), )
Bukan kode UI yang paling indah, pasti. Kata flutter
mana-mana dan bertanya. untuk menyembunyikannya (sebenarnya, saya seharusnya menyebut material
paket, bukan flutter
, tetapi bukan esensi), parameter anonim sama sekali tidak jelas, dan nil
ini secara terbuka membingungkan di mana-mana.
Versi 2
Karena sebagian besar kode masih akan menggunakan satu jenis atau fungsi lain dari paket flutter
, kita dapat menggunakan format "dot import" untuk mengimpor paket ke namespace kami dan dengan demikian "menyembunyikan" nama paket:
import . "github.com/flutter/flutter"
Sekarang alih-alih flutter.Text
. Text
kita hanya bisa menulis Text
. Ini biasanya praktik yang buruk, tetapi kami bekerja dengan kerangka kerja, dan impor ini akan secara harfiah di setiap baris. Dari praktik saya, ini adalah kasus persis di mana impor tersebut dapat diterima - misalnya, seperti ketika menggunakan kerangka kerja yang bagus untuk menguji GoConvey .
Mari kita lihat bagaimana kode akan terlihat:
return NewScaffold( NewAppBar( Text("Flutter Go app", nil), ), nil, nil, NewCenter( NewColumn( MainAxisCenterAlignment, nil, []Widget{ Text("You have pushed the button this many times:", nil), Text(fmt.Sprintf("%d", m.counter), ctx.Theme.textTheme.display1), }, ), ), FloatingActionButton( NewIcon(icons.Add), "Increment", m.onPressed, nil, nil, ), )
Sudah lebih baik, tetapi parameter nil-s dan tidak bernama ini ....
Versi 3
Mari kita lihat seperti apa kode itu jika kita menggunakan refleksi (kemampuan untuk memeriksa kode saat program sedang berjalan) untuk menganalisis parameter yang diteruskan. Pendekatan ini digunakan dalam beberapa kerangka kerja HTTP awal on Go ( martini , misalnya), dan dianggap sebagai praktik yang sangat buruk - tidak aman, kehilangan kenyamanan sistem jenisnya, relatif lambat dan menambah keajaiban pada kode - tetapi untuk percobaan Anda dapat mencoba:
return NewScaffold( NewAppBar( Text("Flutter Go app"), ), NewCenter( NewColumn( MainAxisCenterAlignment, []Widget{ Text("You have pushed the button this many times:"), Text(fmt.Sprintf("%d", m.counter), ctx.Theme.textTheme.display1), }, ), ), FloatingActionButton( NewIcon(icons.Add), "Increment", m.onPressed, ), )
Tidak buruk, dan sepertinya versi asli dari Dart, tetapi kurangnya parameter bernama masih sangat menyakitkan mata.
Versi 4
Mari mundur sedikit dan bertanya pada diri sendiri apa yang ingin kita lakukan. Kami tidak perlu secara buta menyalin pendekatan Dart (meskipun itu akan menjadi bonus yang bagus - ada sedikit untuk mengajar orang-orang yang sudah terbiasa dengan Flutter on Dart). Bahkan, kita hanya membuat objek baru dan menetapkan properti padanya.
Bisakah mencoba cara ini?
scaffold := NewScaffold() scaffold.AppBar = NewAppBar(Text("Flutter Go app")) column := NewColumn() column.MainAxisAlignment = MainAxisCenterAlignment counterText := Text(fmt.Sprintf("%d", m.counter)) counterText.Style = ctx.Theme.textTheme.display1 column.Children = []Widget{ Text("You have pushed the button this many times:"), counterText, } center := NewCenter() center.Child = column scaffold.Home = center icon := NewIcon(icons.Add), fab := NewFloatingActionButton() fab.Icon = icon fab.Text = "Increment" fab.Handler = m.onPressed scaffold.FloatingActionButton = fab return scaffold
, " ", . -, â , . -, , .
, UI GTK Qt . , , Qt 5:
QGridLayout *layout = new QGridLayout(this); layout->addWidget(new QLabel(tr("Object name:")), 0, 0); layout->addWidget(m_objectName, 0, 1); layout->addWidget(new QLabel(tr("Location:")), 1, 0); m_location->setEditable(false); m_location->addItem(tr("Top")); m_location->addItem(tr("Left")); m_location->addItem(tr("Right")); m_location->addItem(tr("Bottom")); m_location->addItem(tr("Restore")); layout->addWidget(m_location, 1, 1); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); layout->addWidget(buttonBox, 2, 0, 1, 2);
, - . , , , .
5
, â -. Sebagai contoh:
func Build() Widget { return NewScaffold(ScaffoldParams{ AppBar: NewAppBar(AppBarParams{ Title: Text(TextParams{ Text: "My Home Page", }), }), Body: NewCenter(CenterParams{ Child: NewColumn(ColumnParams{ MainAxisAlignment: MainAxisAlignment.center, Children: []Widget{ Text(TextParams{ Text: "You have pushed the button this many times:", }), Text(TextParams{ Text: fmt.Sprintf("%d", m.counter), Style: ctx.textTheme.display1, }), }, }), }), FloatingActionButton: NewFloatingActionButton( FloatingActionButtonParams{ OnPressed: m.incrementCounter, Tooltip: "Increment", Child: NewIcon(IconParams{ Icon: Icons.add, }), }, ), }) }
! , . ...Params
, . , , Go , , .
-, ...Params
, . (proposal) â " " . , FloatingActionButtonParameters{...}
{...}
. :
func Build() Widget { return NewScaffold({ AppBar: NewAppBar({ Title: Text({ Text: "My Home Page", }), }), Body: NewCenter({ Child: NewColumn({ MainAxisAlignment: MainAxisAlignment.center, Children: []Widget{ Text({ Text: "You have pushed the button this many times:", }), Text({ Text: fmt.Sprintf("%d", m.counter), Style: ctx.textTheme.display1, }), }, }), }), FloatingActionButton: NewFloatingActionButton({ OnPressed: m.incrementCounter, Tooltip: "Increment", Child: NewIcon({ Icon: Icons.add, }), }, ), }) }
Dart! .
6
, . , , , , .
, , , -, â :
button := NewButton(). WithText("Click me"). WithStyle(MyButtonStyle1)
atau
button := NewButton(). Text("Click me"). Style(MyButtonStyle1)
Scaffold- :
Go â , . Dart-, :
New...()
â , . , â " , , , , , , â " .
, , 5- 6- .
"hello, world" Flutter Go:
main.go
package hello import "github.com/flutter/flutter" func main() { flutter.Run(NewMyApp()) }
app.go:
package hello import . "github.com/flutter/flutter"
home_page.go:
package hello import ( "fmt" . "github.com/flutter/flutter" )
!
Kesimpulan
Vecty
, , Vecty . , , , , Vecty DOM/CSS/JS, Flutter , 120 . , Vecty , Flutter Go Vecty .
Flutter
â , . Flutter, .
Go
" Flutter Go?" "" , , , , , Flutter, , , "" . , Go .
, Go . . Go, , , -. â , , .
Go. â , .
Flutter
, Flutter , , . "/ " , Dart ( , , ). Dart, , (, ) DartVM V8, Flutter â Flutter -.
, . . , , 1.0 . , - .
game changer, Flutter , , .
UI â Flutter, .
Referensi