Const yapıcısı gerçekte nasıl çalışır?


112

Dart'ta bir const yapıcı oluşturmanın mümkün olduğunu fark ettim. Dokümantasyonda, constsözcüğün bir derleme zamanı sabiti bir şeyi belirtmek için kullanıldığını söylüyor .

constBir nesneyi oluşturmak için bir kurucu kullandığımda ne olacağını merak ediyordum . Bu, her zaman aynı olan ve derleme zamanında mevcut olan değişmez bir nesne gibi mi? constYapıcı kavramı aslında nasıl işliyor ? Bir sabit kurucunun normal bir kurucudan farkı nedir?

Yanıtlar:


79

Const yapıcısı, "standartlaştırılmış" bir örnek oluşturur.

Yani, tüm sabit ifadeler kanonikleştirilmeye başlar ve daha sonra bu "kanonikleştirilmiş" semboller bu sabitlerin denkliğini tanımak için kullanılır.

Kanonikleştirme:

Birden fazla olası gösterime sahip verileri "standart" bir kanonik gösterime dönüştürmek için bir işlem. Bu, eşdeğerlik için farklı temsilleri karşılaştırmak, farklı veri yapılarının sayısını saymak, tekrarlanan hesaplamaları ortadan kaldırarak çeşitli algoritmaların verimliliğini artırmak veya anlamlı bir sıralama düzeni empoze etmeyi mümkün kılmak için yapılabilir.


Bu, gibi const ifadelerinin const Foo(1, 1)sanal makinede karşılaştırma için yararlı olan herhangi bir kullanılabilir formu temsil edebileceği anlamına gelir .

Sanal makinenin yalnızca değer türünü ve bağımsız değişkenleri bu const ifadesinde oluştukları sırayla hesaba katması gerekir. Ve tabii ki optimizasyon için azaltılırlar.

Aynı standartlaştırılmış değerlere sahip sabitler:

var foo1 = const Foo(1, 1); // #Foo#int#1#int#1
var foo2 = const Foo(1, 1); // #Foo#int#1#int#1

Farklı standartlaştırılmış değerlere sahip sabitler (çünkü imzalar farklıdır):

var foo3 = const Foo(1, 2); // $Foo$int$1$int$2
var foo4 = const Foo(1, 3); // $Foo$int$1$int$3

var baz1 = const Baz(const Foo(1, 1), "hello"); // $Baz$Foo$int$1$int$1$String$hello
var baz2 = const Baz(const Foo(1, 1), "hello"); // $Baz$Foo$int$1$int$1$String$hello

Sabitler her seferinde yeniden oluşturulmaz. Derleme zamanında standartlaştırılırlar ve daha sonra yeniden kullanılabilecekleri özel arama tablolarında (burada kanonik imzaları tarafından karma hale getirilirler) saklanırlar.

PS

#Foo#int#1#int#1Bu örneklerde kullanılan form yalnızca karşılaştırma amacıyla kullanılır ve Dart VM'de gerçek bir standartlaştırma (temsil) biçimi değildir;

Ancak gerçek kanonikleştirme biçimi "standart" kanonik temsil olmalıdır.


82

Lasse'nin Chris Storms blogundaki cevabını harika bir açıklama buluyorum.

Dart Sabit Oluşturucuları

Umarım içeriği kopyalamama aldırış etmezler.

Bu, son alanların güzel bir açıklamasıdır, ancak const yapıcılarını gerçekten açıklamaz. Bu örneklerdeki hiçbir şey aslında yapıcıların sabit kurucular olduğunu kullanmaz. Herhangi bir sınıfın son alanları, const yapıcıları olabilir veya olmayabilir.

Dart'taki bir alan, depolamayı okuyan ve güncelleyen otomatik olarak oluşturulan bir alıcı ve ayarlayıcıyla birleştirilmiş gerçekten anonim bir depolama konumudur ve ayrıca bir yapıcının başlatıcı listesinde başlatılabilir.

Ayarlayıcı olmadan son alan aynıdır, bu nedenle değerini ayarlamanın tek yolu yapıcı başlatıcı listesidir ve bundan sonra değeri değiştirmenin hiçbir yolu yoktur - dolayısıyla "son".

Const yapıcılarının amacı son alanları başlatmak değildir, herhangi bir üretici kurucu bunu yapabilir. Önemli olan derleme zamanı sabit değerleri yaratmaktır: Tüm alan değerlerinin herhangi bir ifade yürütmeden derleme zamanında zaten bilindiği nesneler.

Bu, sınıfa ve kurucuya bazı kısıtlamalar getirir. Bir const oluşturucunun bir gövdesi olamaz (çalıştırılan deyim yok!) Ve sınıfının nihai olmayan alanları olmamalıdır (derleme zamanında "bildiğimiz" değer daha sonra değiştirilememelidir). Başlatıcı listesi ayrıca alanları yalnızca diğer derleme zamanı sabitleriyle başlatmalıdır, bu nedenle sağ taraf "derleme zamanı sabiti ifadeleri" [1] ile sınırlıdır. Ve "const" öneki olmalıdır - aksi takdirde, bu gereksinimleri karşılayan normal bir kurucu elde edersiniz. Bu gayet iyi, sadece bir kurucu değil.

Derleme zamanı sabiti nesnesini gerçekten oluşturmak için bir const yapıcı kullanmak için, daha sonra "yeni" ifadesini "yeni" ifadesinde "const" ile değiştirirsiniz. Bir const-constructor ile hala "new" kullanabilirsiniz ve bu yine de bir nesne oluşturacaktır, ancak bu, derleme zamanı sabiti değil, normal yeni bir nesne olacaktır. Yani: Bir const yapıcı, çalışma zamanında nesneler oluşturmak için normal bir kurucu olarak ve derleme zamanında derleme zamanı sabit nesneler oluşturmak için de kullanılabilir.

Örnek olarak:

class Point { 
  static final Point ORIGIN = const Point(0, 0); 
  final int x; 
  final int y; 
  const Point(this.x, this.y);
  Point.clone(Point other): x = other.x, y = other.y; //[2] 
}

main() { 
  // Assign compile-time constant to p0. 
  Point p0 = Point.ORIGIN; 
  // Create new point using const constructor. 
  Point p1 = new Point(0, 0); 
  // Create new point using non-const constructor.
  Point p2 = new Point.clone(p0); 
  // Assign (the same) compile-time constant to p3. 
  Point p3 = const Point(0, 0); 
  print(identical(p0, p1)); // false 
  print(identical(p0, p2)); // false 
  print(identical(p0, p3)); // true! 
}

Derleme zamanı sabitleri standartlaştırılmıştır. Bu, kaç kez "sabit Nokta (0,0)" yazarsanız yazın, yalnızca bir nesne oluşturduğunuz anlamına gelir. Bu yararlı olabilir - ancak göründüğü kadar değil, çünkü değeri tutmak için bir const değişkeni oluşturabilir ve onun yerine değişkeni kullanabilirsiniz.

Peki, derleme zamanı sabitleri neye yarar?

  • Numaralandırmalar için kullanışlıdırlar.
  • Anahtar durumlarda derleme zamanı sabiti değerlerini kullanabilirsiniz.
  • Ek açıklama olarak kullanılırlar.

Derleme zamanı sabitleri, Dart değişkenleri tembel olarak başlatmaya geçmeden önce daha önemliydi. Bundan önce, yalnızca "var x = foo;" gibi başlatılmış bir global değişken bildirebilirdiniz. "foo" bir derleme zamanı sabiti ise. Bu gereklilik olmadan, çoğu program herhangi bir const nesnesi kullanılmadan yazılabilir.

Yani, kısa özet: Const yapıcıları sadece derleme zamanı sabit değerleri oluşturmak içindir.

/ L

[1] Veya gerçekten: "Potansiyel olarak derleme zamanı sabiti ifadeleri" çünkü aynı zamanda yapıcı parametrelerine de başvurabilir. [2] Yani evet, bir sınıf aynı anda hem const hem de const olmayan kuruculara sahip olabilir.

Bu konu ayrıca bazı ilginç yorumlarla https://github.com/dart-lang/sdk/issues/36079 adresinde tartışıldı .


AFAIK const ve final, daha optimize edilmiş JS oluşturmaya izin verir.
Günter Zöchbauer

2
Yöntem imzalarındaki varsayılan değerler için de kullanışlıdırlar.
Florian Loitsch

1
Biri bana bu çizginin nasıl çalıştığını açıklayabilir mi? Point.clone(Point other): x = other.x, y = other.y;
Daksh Gargas

Hangi kısım belirsiz? İlgili görünmüyorconst
Günter Zöchbauer

3
constMedium.com/@mehmetf_71205/inheriting-widgets-b7ac56dbbeb1 adresine göre Flutter widget'ları için güzel bir performans kazanımıdır "Widget'larınızı oluşturmak için const kullanın Const olmadan, alt ağacın seçici olarak yeniden oluşturulması gerçekleşmez. Flutter her birinin yeni bir örneğini oluşturur alt ağaçta pencere öğesi ve özellikle derleme yöntemleriniz ağırsa, değerli döngüleri boşa harcayan build () öğesini çağırır.
David Chandler

8

Ayrıntılı olarak çok iyi açıklanmıştır, ancak aslında bir sabit kurucunun kullanımını arayan kullanıcılar için

Flutter'ın yalnızca güncellenmesi gereken widget'ları yeniden oluşturmasına yardımcı olduğu için Flutter Performansını Artırmak için kullanılır.

Örnekle açıklanabilir->

    class _MyWidgetState extends State<MyWidget> {

  String title = "Title";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Column(
        children: <Widget>[
          const Text("Text 1"),
          const Padding(
            padding: const EdgeInsets.all(8.0),
            child: const Text("Another Text widget"),
          ),
          const Text("Text 3"),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          setState(() => title = 'New Title');
        },
      ),
    );
  }
}

Bu örnekte olduğu gibi, yalnızca Metin başlığı değiştirilmelidir, bu nedenle yalnızca bu widget yeniden oluşturulmalıdır, bu nedenle diğer tüm widget'ları const yapıcı olarak yapmak, performansı artırmak için flutter'ın aynısını yapmasına yardımcı olacaktır.


0

Const örneğinin gerçekten son alana göre karar verdiği örnek bir demo.
Ve bu durumda, derleme zamanında tahmin edilemez.

import 'dart:async';

class Foo {
  final int i;
  final int j = new DateTime.now().millisecond;
  const Foo(i) : this.i = i ~/ 10;

  toString() => "Foo($i, $j)";
}



void main() {
  var f2 = const Foo(2);
  var f3 = const Foo(3);

  print("f2 == f3 : ${f2 == f3}"); // true
  print("f2 : $f2"); // f2 : Foo(0, 598)
  print("f3 : $f3"); // f3 : Foo(0, 598)

  new Future.value().then((_) {
    var f2i = const Foo(2);
    print("f2 == f2i : ${f2 == f2i}"); // false
    print("f2i : $f2i"); // f2i : Foo(0, 608)
  });
}

Şimdi dart onu kontrol edecek.

Dart Analizi:

[dart] 'j' alanı sabit olmayan bir değerle başlatıldığından 'const' yapıcısı tanımlanamıyor

Çalışma hatası:

/main.dart ': hata: 5. satır konum 17: ifade geçerli bir derleme zamanı sabiti değil final int j = yeni DateTime.now (). milisaniye;

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.