草庐IT

Flutter: Dart 参数,以及 @required 与 required

小公鸡卡哇伊呀~ 2023-04-05 原文

1. Dart 参数

Dart 函数的参数分 3 种类型:

  • 位置参数
  • 命名参数
  • 可选位置参数

1.1 位置参数 (positional parameters)

参数位置重要,名称任意,

// 定义
void debugger(String message, int lineNum) {}

// 调用
debugger('A bug!', 55);

参数不能多,不能少,实参与形参从左到右一一按位置对应,这是最基本的参数。

1.2 命名参数 (named Parameters)

命名参数:一般函数参数个数数量较多,比如有几十个,按位置传递参数的方法容易出错,不现实。此时可使用命名参数。对于命名参数,参数位置无关紧要,名称重要。
定义函数时,将参数放在花括号中,调用时,指定参数名称。

// 定义
void debugger({String message, int lineNum}) {}

// 调用,位置无关紧要,
// 写成 debugger(lineNum: 44, message: 'A bug!'); 也可以
debugger(message: 'A bug!', lineNum: 44);  

命名参数默认可选,如果需要指定要求参数必须提供,可使用 @required 或者 required,具体用哪一个,与 Dart 版本相关。

如果使用 Dart 1.12 及以后的版本,下面的函数,因为变量默认为 sound null safety(可靠的空安全),函数

void debugger({String message}) {}

要么改成

void debugger({required String message}) {}

要么改成

void debugger({String? message}) {}

1.3 可选位置参数 (optional positional parameters)

放在中括号中的参数是可选位置参数,例如,以下代码中的参数 z

int addSomeNums(int x, int y, [int z]) {
  int sum = x + y;
  if (z != null) {
    sum += z;
  }
  return sum;
}

addSomeNums(5, 4); // okay, because the third parameter z is optional 
addSomeNums(5, 4, 3); // also okay

可选位置参数可以指定默认值:

// function signature 
int addSomeNums(int x, int y, [int z = 5]) => x + y + z;

// calling that function without passing in the third argument
int sum = addSomeNums(5, 6);
assert(sum == 16); // 5 + 6 + 5

// calling that function with passing in the third argument
int sum2 = addSomeNums(5, 6, 10);
assert(sum2 == 21); // 5 + 6 + 10

方括号 [ ] 中的所有参数全部可选, 也就是说,它们必须为 nullable,对于 Dart 1.12 及以后的版本,可以在参数类型后加?,允许其值为 nullDart 1.11 及之前的版本不需要加。

void optionalThreeGreeting(int numberOfTimes,
    [String? name1, String? name2, String? name3]) {
}

1.4 参数组合形式

  • 位置参数
  • 命名参数
  • 可选位置参数
  • 位置参数 + 命名参数
// ✅
String greeting(String name, {String? message}) { ... }
  • 位置参数 + 可选位置参数
// ✅
void hide(bool hidden, [bool? animated]) { ... }

不能混合命名参数与可选位置参数:

// ❌
int mixedSum({required int a, int? b}, [int? c]) { ... }

2. @requiredrequired 的区别


As of Dart 2.12, the required keyword replaces the @required meta annotation. For detailed info look into the official FAQ. The following answer has been updated to reflect both this and null safety.

@required is just an annotation that allows analyzers let you know that you’re missing a named parameter and that’s it. so you can still compile the application and possibly get an exception if this named param was not passed.
However sound null-safety was added to dart, and required is now a keyword that needs to be passed to a named parameter so that it doesn’t let the compiler run if this parameter has not been passed. It makes your code more strict and safe.
If you truly think this variable can be null then you would change the type by adding a ? after it so that the required keyword is not needed, or you can add a default value to the parameter.


Dart 1.12 版开始,使用关键字 required 取代 @required 标记 (同时预设开启sound null safety, 没有特别说明的type 都是 non-nullable 的。)

void debugger({String message, int lineNum}) {}

命名参数默认可选,但是如果要求调用此函数时必须提供哪些参数,对于 Dart 1.12 之前的版本,使用 @required annotation,对于 Dart 1.12 以及之后的版本,使用 required keyword

以下是一个 Flutter project, 设置 pubspec.yaml 中的 Dart 版本:

environment:
  sdk: ">=2.11.0 <3.0.0"

测试函数 func

class _MyHomePageState extends State<MyHomePage> {

  // function for test
  void func({ String arg1,  int arg2}) {
    print(arg1);
    print(arg2);
  }

  
  Widget build(BuildContext context) {
  	// Ok,compile pass
  	// 使用 @required 标记, 分析器会指出命名参数丢失,
  	// 但对实际编译运行没有影响。
    func(); 
    
    return Scaffold(
      appBar: AppBar(
        title: const Text("title"),
      ),
      body: const Center(child: Text('body')),
    );
  }
}

如果改为使用 Dart 2.12,同时 @required 改为 required,此时如果丢失参数,将无法通过编译。

所以,required 作为关键字强制要求提供参数@required 只是一种标记required 强于 @required

environment:
  sdk: ">=2.17.6 <3.0.0"
class _MyHomePageState extends State<MyHomePage> {
  void func({required String arg1, required int arg2}) {
    print(arg1);
    print(arg2);
  }

  
  Widget build(BuildContext context) {
  
	// 无法通过编译 !!!
	// Error: Required named parameter 'arg1' must be provided.
    func();

    return Scaffold(
      appBar: AppBar(
        title: const Text("title"),
      ),
      body: const Center(child: Text('body')),
    );
  }
}

  1. https://flutterbyexample.com/lesson/function-arguments-default-optional-named
  2. https://ithelp.ithome.com.tw/articles/10271892?sc=hot
  3. https://stackoverflow.com/questions/54181838/flutter-required-keyword
  4. https://stackoverflow.com/questions/67642000/what-is-the-difference-between-required-and-required-in-flutter-what-is-the-di
  5. https://stackoverflow.com/questions/64621051/how-to-enable-null-safety-in-flutter
  6. https://sarunw.com/posts/dart-parameters/#how-to-declare-parameters-in-dart

有关Flutter: Dart 参数,以及 @required 与 required的更多相关文章

  1. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  4. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  5. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

随机推荐