【问题标题】:How to create private variables in Dart?如何在 Dart 中创建私有变量?
【发布时间】:2013-07-03 12:58:44
【问题描述】:

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

这是我的代码:

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

【问题讨论】:

    标签: dart


    【解决方案1】:

    来自 Dart 文档:

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

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

    关于图书馆的几句话:

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

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

    【讨论】:

    • 什么定义了库?
    • 问:什么定义了库?答:答案中添加了一个小补充。
    【解决方案2】:

    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
    

    【讨论】:

    • 这应该是公认的答案,因为原始问题已经使用下划线将标识符表示为私有。
    • 感谢这一行“Dart 中的隐私存在于库中,而不是类级别”
    【解决方案3】:

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

    【讨论】:

    • 真是个糟糕的概念。这种方式无法在不同的文件中扩展/实现,或者你必须将其公开,这也有点太多了。
    • 基于文件级别而不是类级别是回答这个问题 IMO 的 核心 部分,这是公认的答案完全跳过的部分 - 假设读者已经明白“对其库私有”的意思是“仅在同一个文件中可用”(除了“part”关键字,在讨论时没有先解释为什么它是相关的)。
    【解决方案4】:

    目前的最佳答案肯定是正确的。

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

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

    既然我们已经解决了这个问题,我将首先向您展示它是如何完成的(library-private 而不是 class-private),然后向您展示如何创建一个变量类-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 中的库部分也是一个很好的资源。
    • 这不是在你的第一个 sn-p _val 中隐含地得到一个 getter 和一个 setter 吗?
    • Offtopic:MyClass.fromVal(int val) : _val = val; - 这是制作静态方法的方式吗?
    猜你喜欢
    • 2016-04-19
    • 2015-12-20
    • 2011-05-08
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2011-02-21
    • 2015-10-11
    相关资源
    最近更新 更多