Flutter符号表管理插件belatuk_symbol_table的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter符号表管理插件belatuk_symbol_table的使用

Pub Version (包括预发布版本) 空安全 许可证

包含重大更改以支持NNBD的package:symbol_table的替代品。

这是一个在Dart中实现的通用符号表库,支持作用域和常量。生成的符号表是分层的(在这种情况下,树形),并利用基本的缓存来加速重复查找。

变量

要表示一个符号,可以使用Variable。我选择使用名称Variable是为了避免与Dart的原始类型Symbol冲突。

var foo =  Variable<String>('foo');
var bar =  Variable<String>('bar', value: 'baz');

// 调用`lock`将符号标记为不可变。
var shelley =  Variable<String>('foo', value: 'bar')..lock();

foo.value = 'bar';
shelley.value = 'Mary'; // 抛出一个StateError - 常量不能被覆盖。

foo.lock();
foo.value = 'baz'; // 同样抛出一个StateError - 一旦变量被锁定,就不能被覆盖。

可见性

变量默认是公开的,但也可以标记为私有或受保护。这在你尝试确定哪些符号应该从库或类中导出时非常有用。

myVariable.visibility = Visibility.protected;
myVariable.visibility = Visibility.private;

符号表

创建一个基本的符号表很容易:

var mySymbolTable =  SymbolTable<int>();
var doubles =  SymbolTable<double>(values: {
  'hydrogen': 1.0,
  'avogadro': 6.022e23
});

// 在当前作用域内创建一个新的变量。
doubles.create('one');
doubles.create('one', value: 1.0);
doubles.create('one', value: 1.0, constant: true);

// 设置一个变量在祖先作用域中,或者如果不存在则创建一个新变量。
doubles.assign('two', 2.0);

// 完全移除一个变量。
doubles.remove('two');

// 查找一个符号,要么在这个符号表中,要么在祖先中。
var symbol = doubles.resolve('one');

// 查找或创建一个符号。
var symbol = doubles.resolveOrCreate('one');
var symbol = doubles.resolveOrCreate('one', value: 1.0);
var symbol = doubles.resolveOrCreate('one', value: 1.0, constant: true);

导出符号

由于符号表的树结构,提取一个线性的唯一变量列表变得非常简单,层次较低的变量会覆盖其父级变量(有效地实现了变量遮蔽)。

var allSymbols = mySymbolTable.allVariables;

我们还可以提取非私有的符号。这有助于我们从库或类中导出符号。

var exportedSymbols = mySymbolTable.allPublicVariables;

提取具有特定可见性的符号也很容易:

var exportedSymbols = mySymbolTable.allVariablesWithVisibility(Visibility.protected);

子作用域

有三种方式可以创建一个新的符号表:

普通子作用域

大多数解释器需要这种方式;它只是创建一个以当前符号表作为父级的新符号表。新作用域可以定义自己的符号,这些符号只会在其正确的范围内遮蔽祖先。

var child = mySymbolTable.createChild();
var child = mySymbolTable.createChild(values: {...});
深度

每个符号表都有一个关联的depth值,根的深度为0。当调用createChild时,生成的子作用域的depth会递增。

克隆

这会在当前级别创建一个具有所有相同变量的作用域。

var clone = mySymbolTable.clone();

分叉作用域

如果你正在实现一个带有闭包函数的语言,可以考虑这种方法。分叉作用域与当前作用域完全相同,但不是仅仅复制变量的引用,而是将变量的值复制到新的变量中。

新的作用域基本上是一个“冻结”的当前作用域。

它也是有效地孤立的——尽管它意识到它的parent,但父作用域并不知道分叉作用域是一个子作用域。因此,如果父级调用了removeresolve可能返回旧的变量。

var forked = mySymbolTable.fork();
var forked = mySymbolTable.fork(values: {...});

创建名称

在具有块作用域的语言中,标识符通常会在全局作用域中发生冲突。为了避免这种情况,符号表暴露了一个uniqueName()方法,该方法只是给输入名称附加一个数字后缀。名称保证在一个特定的作用域内不会重复。

var name0 = mySymbolTable.uniqueName('foo'); // foo0
var name1 = mySymbolTable.uniqueName('foo'); // foo1
var name2 = mySymbolTable.uniqueName('foo'); // foo2

this上下文

许多语言处理一种this上下文,其中作用域内的值可以选择性地解析。符号表可以轻松设置其上下文如下:

void foo() {
  mySymbolTable.context = thisContext;
}

context的解析就像解析一个符号一样工作;如果本地没有设置,则它将引用父级。

void bar() {
  mySymbolTable.context = thisContext;
  expect(mySymbolTable.createChild().createChild().context, thisContext);
}

示例代码

import 'package:belatuk_symbol_table/belatuk_symbol_table.dart';

void main(List<String> args) {
  //var mySymbolTable = SymbolTable<int>();
  var doubles =
      SymbolTable<double>(values: {'hydrogen': 1.0, 'avogadro': 6.022e23});

  // 在当前作用域内创建一个新的变量。
  doubles.create('one');
  doubles.create('one', value: 1.0);
  doubles.create('one', value: 1.0, constant: true);

  // 设置一个变量在祖先作用域中,或者如果不存在则创建一个新变量。
  doubles.assign('two', 2.0);

  // 完全移除一个变量。
  doubles.remove('two');

  // 查找一个符号,要么在这个符号表中,要么在祖先中。
  // var symbol1 = doubles.resolve('one');

  // 查找或创建一个符号。
  // var symbol2 = doubles.resolveOrCreate('one');
  // var symbol3 = doubles.resolveOrCreate('one', value: 1.0);
  // var symbol4 = doubles.resolveOrCreate('one', value: 1.0, constant: true);
}

更多关于Flutter符号表管理插件belatuk_symbol_table的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter符号表管理插件belatuk_symbol_table的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用belatuk_symbol_table插件的示例代码案例。belatuk_symbol_table插件用于管理符号表,这在处理动态符号解析、变量存储等场景时非常有用。

首先,确保你已经在pubspec.yaml文件中添加了belatuk_symbol_table依赖:

dependencies:
  flutter:
    sdk: flutter
  belatuk_symbol_table: ^最新版本号  # 请替换为实际的最新版本号

然后运行flutter pub get来获取依赖。

接下来,你可以在Flutter项目中创建一个简单的示例来演示如何使用belatuk_symbol_table

import 'package:flutter/material.dart';
import 'package:belatuk_symbol_table/belatuk_symbol_table.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Symbol Table Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SymbolTableDemo(),
    );
  }
}

class SymbolTableDemo extends StatefulWidget {
  @override
  _SymbolTableDemoState createState() => _SymbolTableDemoState();
}

class _SymbolTableDemoState extends State<SymbolTableDemo> {
  final SymbolTable _symbolTable = SymbolTable();

  void _addToSymbolTable(String key, dynamic value) {
    _symbolTable.defineSymbol(key, value);
    setState(() {});
  }

  dynamic _getFromSymbolTable(String key) {
    return _symbolTable.resolveSymbol(key);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Symbol Table Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextField(
              decoration: InputDecoration(
                labelText: 'Key',
              ),
              onChanged: (key) {
                // Handle key input
              },
            ),
            SizedBox(height: 16),
            TextField(
              decoration: InputDecoration(
                labelText: 'Value',
              ),
              onChanged: (value) {
                // Handle value input
              },
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                // Example: Adding a string value
                String key = 'exampleKey';
                String value = 'exampleValue';
                _addToSymbolTable(key, value);

                // Display the value to verify
                String resolvedValue = _getFromSymbolTable(key) as String;
                print('Resolved Value: $resolvedValue');
              },
              child: Text('Add to Symbol Table'),
            ),
            SizedBox(height: 16),
            Text('Symbol Table Contents:'),
            SizedBox(height: 8),
            Expanded(
              child: ListView.builder(
                itemCount: _symbolTable.symbols.length,
                itemBuilder: (context, index) {
                  final symbol = _symbolTable.symbols.keys.elementAt(index);
                  final value = _symbolTable.resolveSymbol(symbol);
                  return ListTile(
                    title: Text('$symbol: $value'),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个SymbolTable实例。你可以通过点击按钮将键值对添加到符号表中,并在ListView中显示符号表的内容。

注意:

  • SymbolTabledefineSymbol方法用于定义符号。
  • resolveSymbol方法用于解析符号并获取其值。

实际应用中,你可能需要更复杂的逻辑来处理输入和输出,但这个示例提供了一个基本的框架,展示了如何在Flutter项目中使用belatuk_symbol_table插件。

回到顶部