如何在Dart中创建私有变量?


80

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

这是我的代码:

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

Answers:


143

从Dart文档中:

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

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

关于库的几句话:

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

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


2
图书馆的定义是什么?
CodeGrue

问:图书馆的定义是什么?答:答案中添加了少量内容。
mezoni

54

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

3
这应该是可接受的答案,因为原始问题已经使用下划线将标识符表示为私有。
Nick Korostelev '18

1
感谢这一行“ Dart的隐私存在于图书馆,而不是课堂一级”
Shahriar Nasim Nafi

10

到目前为止,最重要的答案肯定是正确的。

我将尝试在此答案中更详细地说明。

我将回答这个问题,但首先提出:这不是Dart的编写意图,部分原因是私有库成员使像这样的定义运算符更加容易==。(无法看到第二个对象的私有变量进行比较。)

现在我们已经解决了这个问题,我将首先向您展示它是如何完成的(库私有而不是class-private),然后向您展示如何使变量成为class-private(如果有)。你仍然真的想要那个。开始了。

如果一个类没有业务看到另一个类上的变量,则您可能会问自己,它们是否真正属于同一库:

    //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,则应该使用它。或者,甚至更好地使用内联函数类型。

如果使用第二个,它的详细程度会降低,但其他问题仍然存在。


Effective Dart中的“库”部分也是一个很好的资源。
AaronF

这不是在您的第一个代码段中_val隐式地得到一个getter和setter吗?
下雨

题外话:MyClass.fromVal(int val) : _val = val;-这是制作静态方法的方法吗?
声波

3

在dart中,变量名之前使用_,以将其声明为私有。与其他编程语言不同,这里的private并不意味着它仅对它所在的类可用,private意味着它可以在其所在的文件中访问,而其他文件则不能访问。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.