web-dev-qa-db-ja.com

Dartでプライベート変数を作成する方法は?

プライベート変数を作成したいのですが、できません。

ここに私のコードがあります:

void main() {
  var b = new B();
  b.testB();    
}

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');
    _private = 5;
  }
}

class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private');
    testA();
    print('String value: $_private');
  }
}

このコードを実行すると、次の結果が得られます。

String value: Hello
int value: Hello
Breaking on exception: type 'int' is not a subtype of type 'String' of 'value'.

また、このソースコードを編集するときにエラーや警告は表示されません。

Dartでプライベート変数を作成するにはどうすればよいですか?

39
user2553310

Dartドキュメントから:

Javaとは異なり、Dartにはキーワードpublic、protected、およびprivateがありません。識別子がアンダースコア_で始まる場合、そのライブラリに対してプライベートです。

ライブラリはAPIを提供するだけでなく、プライバシーの単位です。アンダースコア_で始まる識別子は、ライブラリ内でのみ表示されます。

70
mezoni

Dartのプライバシーは、クラスレベルではなくライブラリに存在します。

クラスAを別のライブラリファイル(たとえば、other.Dart)、 といった:

library other;

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');  // 0
    _private = 5;
    print('int value: $_private'); // 5
  }
}

次に、次のようなメインアプリにインポートします。

import 'other.Dart';

void main() {
  var b = new B();
  b.testB();    
}


class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private'); // Hello
    testA();
    print('String value: $_private'); // Hello
  }
}

期待される出力が得られます:

String value: Hello
int value: 0
int value: 5
String value: Hello
23
Chris Buckett

現在のトップの答えは間違いなく正しいです。

この回答ではさらに詳しく説明します。

私は質問に答えますが、これで導きます:ライブラリプライベートメンバーが==のような演算子を定義するのを簡単にするため、それはDartが書かれることを意図している方法ではありません。 (2番目のオブジェクトのプライベート変数は、比較のために見ることができませんでした。)

これで邪魔にならないようになったので、まずそれがどのように行われるのか(クラスプライベートではなくライブラリプライベート)を示すことから始め、次に変数をクラスプライベートにする方法を示します。あなたはまだそれを本当に望んでいます。さあ行こう。

あるクラスに別のクラスの変数を参照するビジネスがない場合、それらが同じライブラリに本当に属しているかどうかを自問することができます。

    //This should be in a separate library from main() for the reason stated in the main method below.

    class MyClass {
      //Library private variable
      int _val = 0;

      int get val => _val;
      set val(int v) => _val = (v < 0) ? _val : v;

      MyClass.fromVal(int val) : _val = val;
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.val = -1;
      print(mc.val); //1

      //main() MUST BE IN A SEPARATE LIBRARY TO 
      //PREVENT MODIFYING THE BACKING FIELDS LIKE:
      mc._val = 6;
      print(mc.val); //6
    }

それは良いはずです。ただし、reallyプライベートクラスデータが必要な場合:

技術的にプライベート変数を作成することは許可されていませんが、次のクロージャ手法を使用してcouldエミュレートできます。

(ただし、本当に必要かどうか、達成しようとしていることを行うためのより良い、よりダート的な方法があるかどうかを慎重に検討する必要があります!)

    //A "workaround" that you should THINK TWICE before using because:
    //1. The syntax is verbose.
    //2. Both closure variables and any methods needing to access
    //   the closure variables must be defined inside a base constructor.
    //3. Those methods require typedefs to ensure correct signatures.

    typedef int IntGetter();
    typedef void IntSetter(int value);

    class MyClass {
      IntGetter getVal;
      IntSetter setVal;

      MyClass.base() {
        //Closure variable
        int _val = 0;

        //Methods defined within constructor closure
        getVal = ()=>_val;
        setVal = (int v) => _val = (v < 0) ? _val : v;
      }

      factory MyClass.fromVal(int val) {
        MyClass result = MyClass.base();
        result.setVal(val);
        return result;
      }
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.setVal(-1); //Fails
      print(mc.getVal());

      //On the upside, you can't access _val
      //mc._val = 6; //Doesn't compile.
    }

ええ注意して、言語のベストプラクティスに従うようにしてください。

[〜#〜] edit [〜#〜]

どうやらDart 2に適した新しいtypedef構文があります。Dart2を使用している場合は、それを使用する必要があります。または、さらに良いことに、インライン関数型を使用します。

2番目を使用すると、冗長性は低くなりますが、他の問題は残ります。

5
AaronF