106

我想创建一个私有变量,但我不能。

这是我的代码:

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 中创建私有变量?

4

4 回答 4

182

来自 Dart 文档:

与 Java 不同,Dart 没有关键字 public、protected 和 private。如果标识符以下划线开头_,则它对其库是私有的。

库不仅提供 API,而且是一个隐私单元:以下划线开头的标识符_仅在库内可见。

关于图书馆的几句话:

每个 Dart 应用程序都是一个库,即使它不使用库指令。导入和库指令可以帮助您创建模块化和可共享的代码库。

您可能听说过该part指令,它允许您将一个库拆分为多个 Dart 文件。

于 2013-07-05T12:23:16.250 回答
77

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
于 2013-07-05T12:22:36.043 回答
18

dart' _' 之前使用 将variable name其声明为private。与其他编程语言不同,这里private并不意味着它只对它所在的类可用,private 意味着它可以在它所在的文件中访问,而其他文件无法访问

于 2020-07-09T03:46:41.563 回答
13

截至目前的最佳答案绝对是正确的。

我将尝试在此答案中更详细地介绍。

我会回答这个问题,但首先要说明的是:这不是 Dart 的预期编写方式,部分原因是库私有成员可以更容易地定义像==. (无法看到第二个对象的私有变量进行比较。)

既然我们已经解决了这个问题,我将首先向您展示它是如何完成的(library-private 而不是 class-private),然后向您展示如何使变量 class-private if你还是真的想要那个。开始了。

如果一个类无法查看另一个类的变量,您可能会问自己它们是否真的属于同一个库:

    //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
    }

那应该很好。但是,如果您真的想要私有类数据:

虽然技术上不允许您创建私有变量,但您可以使用以下闭包技术来模拟它。

(然而,你应该仔细考虑你是否真的需要它,以及是否有更好、更类似于 Dart 的方式来完成你想要完成的事情!)

    //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.
    }

是的。请小心并尝试遵循语言的最佳实践,您应该会没事的。

编辑

显然有一个新的 typedef 语法是 Dart 2 的首选。如果你使用的是 Dart 2,你应该使用它。或者,更好的是,使用内联函数类型。

如果您使用第二个,它将不那么冗长,但其他问题仍然存在。

于 2018-11-03T19:53:05.790 回答