本文分享我在flutter编程中的重要技巧,学会了您的代码风格将得到很大提高。1。你知道吗,Dart支持字符串乘法。 下面的例子如何用字符串乘法打印圣诞树voidmain(){for(vari1;i5;i){print(i);}}Output: 是不是很酷? 你可以用它来检查在Textwidget中文本的长度是否合适。Text(Youhavepushedthebuttonthismanytimes:5)2。需要同时执行多个Future?使用Future。wait。 ConsiderthismockAPIclassthattellsusthelatestnumbersofCOVIDcases:MockAPIclassclassCovidAPI{FutureintgetCases()Future。value(1000);FutureintgetRecovered()Future。value(100);FutureintgetDeaths()Future。value(10);} 要同时执行这些future,使用Future。wait。参数需要futures的list并且会返回一个future的list:finalapiCovidAPI();finalvaluesawaitFuture。wait(〔api。getCases(),api。getRecovered(),api。getDeaths(),〕);print(values);〔1000,100,10〕 当Future是独立的并且不需要顺序执行时,这样做起来就很理想。3。可以在Dart的class中实现一个call方法,这样我们就可以像调用方法一样调用类。 下面是一个PasswordValidatorclass:classPasswordValidator{boolcall(Stringpassword){returnpassword。length10;}} 我们定义了一个call方法,再定义一个类的实例就可以像使用函数一样使用它:finalvalidatorPasswordValidator();canuseitlikethis:validator(test);validator(test1234);noneedtouseitlikethis:validator。call(notsofrozenarctic);4。需要调用回调方法,但前提是回调方法不为空?使用?。call()语法。 在下面的列子中我们定义了一个widget,并且要在事件触发时调用onDragCompleted回调:classCustomDraggableextendsStatelessWidget{constCustomDraggable({Keykey,this。onDragCompleted}):super(key:key);finalVoidCallback?onDragCvoiddragComplete(){TODO:Implementme}overrideWidgetbuild(BuildContextcontext){。。。}} 为了调用回调函数,我们可能要写如下的代码:voiddragComplete(){if(onDragCompleted!null){onDragCompleted();}} 但是我们可以使用如下的简单语法(使用?。):FuturevoiddragComplete()async{onDragCompleted?。call();}5。使用匿名函数和函数作为参数 在Dart中,函数是一等公民,并且能够作为其他函数的参数。 下面演示了定义一个匿名函数,并且赋值给sayHi变量:voidmain(){finalsayHi(name)Hi,welcome(sayHi,Andrea);}voidwelcome(StringFunction(String)greet,Stringname){print(greet(name));print(Welcometothiscourse);} 将sayHi作为变量传给welcome方法的greet参数。 StringFunction(String)是一个函数类型,带有String参数并且返回String类型。因为上面的匿名函数具有相同的signature,所以能够直接作为参数传递。 在list的map,where,reduce等操作时,这样的代码风格很常见。 举个计算数的平方的例子:intsquare(intvalue){} 计算出数组的所有平方:constvalues〔1,2,3〕;values。map(square)。toList(); 这里使用square作为参数,因为square的signature是符合map操作期望的。所以我们可以不使用下面的匿名函数:values。map((value)square(value))。toList();6。可以将collectionif和spreads与列表、集合和map一起使用 Collectionifandspreads在我们写代码时非常有用。 这些其实也可以和map一起使用。 看下面的例子:constaddRconstrestaurant{name:PizzaMario,cuisine:Italian,if(addRatings)。。。{avgRating:4。3,numRatings:5,}}; 我们定义了一个restaurant的map,并且只有当addRatings是true的时候才会添加avgRatingandnumRatings。因为超过了一个keyvalue,所以需要使用spread操作符(。。。)。7。如何以nullsafe的方法遍历整个map?使用。entries: 看下面的一个例子:consttimeSpentString,double{Blogging:10。5,YouTube:30。5,Courses:75。2,}; 下面是循环遍历keyvalue:for(varentryintimeSpent。entries){dosomethingwithkeysandvaluesprint({entry。key}:{entry。value});}8。使用命名构造函数和初始化列表使API更简洁。 比如我们要定义一个温度的类。 需要让我们的类支持两个摄氏和华氏两种命名构造函数:classTemperature{Temperature。celsius(this。celsius);Temperature。fahrenheit(doublefahrenheit):celsius(fahrenheit32)1。8;} 该类只需要一个变量来表示温度,并使用初始化列表将华氏温度转换为摄氏温度。 我们在使用时就可以像下面这样:finaltemp1Temperature。celsius(30);finaltemp2Temperature。fahrenheit(90);9。Gettersandsetters 在上面的Temperature类中,celsius用来表示温度。 但是有些用户可能喜欢华氏温度。 我们可以很容易通过gettersandsetters实现,定义computed变量(学过vue的是不是感觉很熟悉)。继续看下面的例子:classTemperature{Temperature。celsius(this。celsius);Temperature。fahrenheit(doublefahrenheit):celsius(fahrenheit32)1。8;doublegetfahrenheitcelsius1。832;setfahrenheit(doublefahrenheit)celsius(fahrenheit32)1。8;} 这下我们使用华氏温度或者摄氏温度就很容易了:finaltemp1Temperature。celsius(30);print(temp1。fahrenheit);finaltemp2Temperature。fahrenheit(90);temp2。celsius28; 提示:使用命名构造函数、getter和setter来改进类的设计。10。未使用的参数使用下划线表示 举一个常见的例子ListView。builder:classMyListViewextendsStatelessWidget{overrideWidgetbuild(BuildContextcontext){returnListView。builder(itemBuilder:(context,index)ListTile(title:Text(allthesame),),itemCount:10,);}} 上面的例子中我们没有使用itemBuilder的的参数(context,index)。因此我们可以使用下划线代替。ListView。builder(itemBuilder:(,)ListTile(title:Text(allthesame),),itemCount:10,) 注意:这两个参数是不同的(和),它们是单独的标识符。11。一个类只需要被初始化一次(单例模式)?使用带有私有构造函数的静态实例变量。 Themostimportantpropertyofasingletonisthattherecanonlybeoneinstanceofitinyourentireprogram。Thisisusefultomodelthingslikeafilesystem。filesystem。dartclassFileSystem{FileSystem。();staticfinalinstanceFileSystem。();} 要在Dart中创建单例,您可以声明一个命名构造函数并使用语法将其设为私有。 然后再定一个final类型的类静态实例。 从此,只能通过instance变量访问这个类。someotherfile。dartfinalfsFileSystem。dosomethingwithfs 注意:如果不小心,单例可能会导致很多问题。在使用它们之前,请确保您了解它们的缺点。12。想要集合中的每一项都是唯一的?使用Set而不是List。 Dart中最常见的集合是List。 list可以有重复的项,有些时候我们想要元素是唯一的:constcitiesList〔London,Paris,Rome,London,〕; 这时候我们就需要使用Set(注意我们使用了final):setisfinal,compilesfinalcitiesSet{London,Paris,Rome,London,Twoelementsinasetliteralshouldntbeequal}; 上面的代码将产生警告,因为London包含了两个。如果把set定义为const,代码将产生错误,并且不能编译成功:setisconst,doesntcompileconstcitiesSet{London,Paris,Rome,London,Twoelementsinaconstantsetliteralcantbeequal}; 我们使用set时,我们可以使用union,difference,andintersectio等APIcitiesSet。union({Delhi,Moscow});citiesSet。difference({London,Madrid});citiesSet。intersection({London,Berlin});13。怎么使用try,on,catch,rethrow,finally 当我们使用基于Future的API时,try和catch是非常有用的。 看看下面的例子:FuturevoidprintWeather()async{try{finalapiWeatherApiClient();finalweatherawaitapi。getWeather(London);print(weather);}onSocketExceptioncatch(){print(Couldnotfetchdata。Checkyourconnection。);}onWeatherApiExceptioncatch(e){print(e。message);}catch(e,st){print(Error:eStacktrace:st);}finally{print(Done);}} 有以下几点需要主要:可以添加多个on来捕获不同类型的异常。最后可以添加一个catch来捕获上面没有处理到的异常。使用rethrow语句将当前异常抛出调用堆栈,同时保留堆栈追踪。使用finally在Future完成后运行一些代码,无论它是成功还是失败。 使用Future相关的API时,一定要确保异常处理14。Future的一些常用构造函数 Future中有一些方便的构造函数:Future。delayed,Future。value和Future。error。 我们可以使用Future。delayed制造一定的延迟。第二个参数是一个(可选的)匿名函数,可以用它来完成一个值或抛出一个错误:awaitFuture。delayed(Duration(seconds:2),()Latte); 有时我们可以创建一个Future并立即返回,这在测试mock数据时非常有用:awaitFuture。value(Cappuccino);awaitFuture。error(Exception(Outofmilk)); 我们可以用Future。value一个值来表示成功完成,或者Future。error表示错误。15。常见的Stream构造函数 Stream类也带有一些方便的构造函数。以下是最常见的:Stream。fromIterable(〔1,2,3〕);Stream。value(10);Stream。empty();Stream。error(Exception(somethingwentwrong));Stream。fromFuture(Future。delayed(Duration(seconds:1),()42));Stream。periodic(Duration(seconds:1),(index)index);使用Stream。fromIterable从list创建Stream。使用Stream。value从一个单一值创建。使用Stream。empty创建一个空的stream。使用Stream。error包含错误值的stram。使用Stream。fromFuture创建一个只包含一个值的stream,并且该值将在未来完成时可用。使用Stream。periodic创建周期性的事件流。16。SyncandAsyncGenerators 我们可以定义一个synchronousgenerator(同步生成器)函数的返回类型定义为Iterable:Iterableintcount(intn)sync{for(vari1;i){}} 这里使用了sync语法。在函数内部,我们可以yield多个值。这些值将在函数完成时作为一个Iterable返回。 另外,一个asynchronousgenerator需要使用Stream作为返回值StreamintcountStream(intn)async{for(vari1;i){}} 这里使用async语法。在函数内部,我们可以yield多个返回值。 在asynchronousgenerator中我们也可以使用Future相关的函数:StreamintcountStream(intn)async{for(vari1;i){dummydelaythiscouldbeanetworkrequestawaitFuture。delayed(Duration(seconds:1));}}最后 希望大家喜欢我提供的这写小技巧,快来使用它们来改进Flutter应用程序中的代码。大家可以留言告诉我,你们最喜欢哪个小技巧!!