专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

golang源码分析protocvalidate

  业务代码中有很多参数校验的代码,如果手动实现,会非常繁琐,https:github。comgoplaygroundvalidator是一个非常不错的选择echo源码分析(validator),但是对于grpc来说,在定义proto的时候使用直接定义参数的限制规则是一种更合理、更优雅的方式,插件https:github。combufbuildprotocgenvalidate就是来帮助我们实现这一功能的。kratos框架也用到了这个插件。下面我们详细介绍下如何安装和使用。
  首先,github上的安装方式并不好使,生成的代码里并没有校验规则,相反我们会得到下面的注释novalidationrulesforIdnovalidationrulesforEmail
  这是因为,这个包的main分支是不稳定版本,按照官方的方式安装并不好使。我们可以安装稳定版本goinstallgithub。comenvoyproxyprotocgenvalidatev0。1。0
  然后我们可以在GOPATH看到这个插件lsGOPATHbinprotocgenvalidatexxxbinprotocgenvalidate
  对应的,我们的protoc版本如下protocversionlibprotoc3。19。4
  然后,可以定义我们的proto文件syntaxproto3;packageexamplepb;optiongopackage。example;importvalidatevalidate。proto;messagePerson{uint64id1〔(validate。rules)。uint64。gt999〕;stringemail2〔(validate。rules)。string。emailtrue〕;stringname3〔(validate。rules)。string{pattern:〔〔09〕AZaz〕(〔〔09〕AZaz〕)34;,maxbytes:256,}〕;Locationhome4〔(validate。rules)。message。requiredtrue〕;参数必须大于0int64ids5〔(validate。rules)。int64{gt:0}〕;参数必须在0到120之间int32age6〔(validate。rules)。int32{gt:0,lte:120}〕;参数是1或2或3uint32code7〔(validate。rules)。uint32{in:〔1,2,3〕}〕;参数不能是0或99。99floatscore8〔(validate。rules)。float{notin:〔0,99。99〕}〕;messageLocation{doublelat1〔(validate。rules)。double{gte:90,lte:90}〕;doublelng2〔(validate。rules)。double{gte:180,lte:180}〕;}}
  使用命令生成go文件protocI。pluginGOPATHbinprotocgenvalidateI{GOPATH}pkgmodgithub。comenvoyproxyprotocgenvalidatev0。1。0goout:。generatedvalidateoutlanggo:。generatedexample。proto
  相应的,我们得到了两个文件
  learnpgvgeneratedexampleexample。pb。goCodegeneratedbyprotocgengo。DONOTEDIT。versions:protocgengov1。28。1protocv3。19。4source:example。protopackageexampleimport(github。comenvoyproxyprotocgenvalidatevalidateprotoreflectgoogle。golang。orgprotobufreflectprotoreflectprotoimplgoogle。golang。orgprotobufruntimeprotoimplreflectreflectsyncsync)const(Verifythatthisgeneratedcodeissufficientlyuptodate。protoimpl。EnforceVersion(20protoimpl。MinVersion)Verifythatruntimeprotoimplissufficientlyuptodate。protoimpl。EnforceVersion(protoimpl。MaxVersion20))typePersonstruct{stateprotoimpl。MessageStatesizeCacheprotoimpl。SizeCacheunknownFieldsprotoimpl。UnknownFieldsIduint64protobuf:varint,1,opt,nameid,proto3json:id,omitemptyEmailstringprotobuf:bytes,2,opt,nameemail,proto3json:email,omitemptyNamestringprotobuf:bytes,3,opt,namename,proto3json:name,omitemptyHomePersonLocationprotobuf:bytes,4,opt,namehome,proto3json:home,omitempty参数必须大于0Idsint64protobuf:varint,5,opt,nameids,proto3json:ids,omitempty参数必须在0到120之间Ageint32protobuf:varint,6,opt,nameage,proto3json:age,omitempty参数是1或2或3Codeuint32protobuf:varint,7,opt,namecode,proto3json:code,omitempty参数不能是0或99。99Scorefloat32protobuf:fixed32,8,opt,namescore,proto3json:score,omitempty}func(xPerson)Reset(){xPerson{}ifprotoimpl。UnsafeEnabled{mi:fileexampleprotomsgTypes〔0〕ms:protoimpl。X。MessageStateOf(protoimpl。Pointer(x))ms。StoreMessageInfo(mi)}}func(xPerson)String()string{returnprotoimpl。X。MessageStringOf(x)}func(Person)ProtoMessage(){}func(xPerson)ProtoReflect()protoreflect。Message{mi:fileexampleprotomsgTypes〔0〕ifprotoimpl。UnsafeEnabledx!nil{ms:protoimpl。X。MessageStateOf(protoimpl。Pointer(x))ifms。LoadMessageInfo()nil{ms。StoreMessageInfo(mi)}returnms}returnmi。MessageOf(x)}Deprecated:UsePerson。ProtoReflect。Descriptorinstead。func(Person)Descriptor()(〔〕byte,〔〕int){returnfileexampleprotorawDescGZIP(),〔〕int{0}}func(xPerson)GetId()uint64{ifx!nil{returnx。Id}return0}func(xPerson)GetEmail()string{ifx!nil{returnx。Email}return}func(xPerson)GetName()string{ifx!nil{returnx。Name}return}func(xPerson)GetHome()PersonLocation{ifx!nil{returnx。Home}returnnil}func(xPerson)GetIds()int64{ifx!nil{returnx。Ids}return0}func(xPerson)GetAge()int32{ifx!nil{returnx。Age}return0}func(xPerson)GetCode()uint32{ifx!nil{returnx。Code}return0}func(xPerson)GetScore()float32{ifx!nil{returnx。Score}return0}typePersonLocationstruct{stateprotoimpl。MessageStatesizeCacheprotoimpl。SizeCacheunknownFieldsprotoimpl。UnknownFieldsLatfloat64protobuf:fixed64,1,opt,namelat,proto3json:lat,omitemptyLngfloat64protobuf:fixed64,2,opt,namelng,proto3json:lng,omitempty}func(xPersonLocation)Reset(){xPersonLocation{}ifprotoimpl。UnsafeEnabled{mi:fileexampleprotomsgTypes〔1〕ms:protoimpl。X。MessageStateOf(protoimpl。Pointer(x))ms。StoreMessageInfo(mi)}}func(xPersonLocation)String()string{returnprotoimpl。X。MessageStringOf(x)}func(PersonLocation)ProtoMessage(){}func(xPersonLocation)ProtoReflect()protoreflect。Message{mi:fileexampleprotomsgTypes〔1〕ifprotoimpl。UnsafeEnabledx!nil{ms:protoimpl。X。MessageStateOf(protoimpl。Pointer(x))ifms。LoadMessageInfo()nil{ms。StoreMessageInfo(mi)}returnms}returnmi。MessageOf(x)}Deprecated:UsePersonLocation。ProtoReflect。Descriptorinstead。func(PersonLocation)Descriptor()(〔〕byte,〔〕int){returnfileexampleprotorawDescGZIP(),〔〕int{0,0}}func(xPersonLocation)GetLat()float64{ifx!nil{returnx。Lat}return0}func(xPersonLocation)GetLng()float64{ifx!nil{returnx。Lng}return0}varFileexampleprotoprotoreflect。FileDescriptorvarfileexampleprotorawDesc〔〕byte{0x0a,0x0d,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x2e,0x70,0x72,0x6f,0x74,0x6f,0x12,0x09,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x70,0x62,0x1a,0x17,0x76,0x61,0x6c,0x69,0x64,0x61,0x74,0x65,0x2f,0x76,0x61,0x6c,0x69,0x64,0x61,0x74,0x65,0x2e,0x70,0x72,0x6f,0x74,0x6f,0x22,0xb5,0x03,0x0a,0x06,0x50,0x65,0x72,0x73,0x6f,0x6e,0x12,0x1a,0x0a,0x02,0x69,0x64,0x18,0x01,0x20,0x01,0x28,0x04,0x42,0x0a,0xba,0xe9,0xc0,0x03,0x05,0x32,0x03,0x20,0xe7,0x07,0x52,0x02,0x69,0x64,0x12,0x1f,0x0a,0x05,0x65,0x6d,0x61,0x69,0x6c,0x18,0x02,0x20,0x01,0x28,0x09,0x42,0x09,0xba,0xe9,0xc0,0x03,0x04,0x72,0x02,0x60,0x01,0x52,0x05,0x65,0x6d,0x61,0x69,0x6c,0x12,0x44,0x0a,0x04,0x6e,0x61,0x6d,0x65,0x18,0x03,0x20,0x01,0x28,0x09,0x42,0x30,0xba,0xe9,0xc0,0x03,0x2b,0x72,0x29,0x28,0x80,0x02,0x32,0x24,0x5e,0x5b,0x5e,0x5b,0x30,0x2d,0x39,0x5d,0x41,0x2d,0x5a,0x61,0x2d,0x7a,0x5d,0x2b,0x28,0x20,0x5b,0x5e,0x5b,0x30,0x2d,0x39,0x5d,0x41,0x2d,0x5a,0x61,0x2d,0x7a,0x5d,0x2b,0x29,0x2a,0x24,0x52,0x04,0x6e,0x61,0x6d,0x65,0x12,0x3a,0x0a,0x04,0x68,0x6f,0x6d,0x65,0x18,0x04,0x20,0x01,0x28,0x0b,0x32,0x1a,0x2e,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x70,0x62,0x2e,0x50,0x65,0x72,0x73,0x6f,0x6e,0x2e,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x42,0x0a,0xba,0xe9,0xc0,0x03,0x05,0x8a,0x01,0x02,0x10,0x01,0x52,0x04,0x68,0x6f,0x6d,0x65,0x12,0x1b,0x0a,0x03,0x69,0x64,0x73,0x18,0x05,0x20,0x01,0x28,0x03,0x42,0x09,0xba,0xe9,0xc0,0x03,0x04,0x22,0x02,0x20,0x00,0x52,0x03,0x69,0x64,0x73,0x12,0x1d,0x0a,0x03,0x61,0x67,0x65,0x18,0x06,0x20,0x01,0x28,0x05,0x42,0x0b,0xba,0xe9,0xc0,0x03,0x06,0x1a,0x04,0x18,0x78,0x20,0x00,0x52,0x03,0x61,0x67,0x65,0x12,0x21,0x0a,0x04,0x63,0x6f,0x64,0x65,0x18,0x07,0x20,0x01,0x28,0x0d,0x42,0x0d,0xba,0xe9,0xc0,0x03,0x08,0x2a,0x06,0x30,0x01,0x30,0x02,0x30,0x03,0x52,0x04,0x63,0x6f,0x64,0x65,0x12,0x27,0x0a,0x05,0x73,0x63,0x6f,0x72,0x65,0x18,0x08,0x20,0x01,0x28,0x02,0x42,0x11,0xba,0xe9,0xc0,0x03,0x0c,0x0a,0x0a,0x3d,0x00,0x00,0x00,0x00,0x3d,0xe1,0xfa,0xc7,0x42,0x52,0x05,0x73,0x63,0x6f,0x72,0x65,0x1a,0x64,0x0a,0x08,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x12,0x2b,0x0a,0x03,0x6c,0x61,0x74,0x18,0x01,0x20,0x01,0x28,0x01,0x42,0x19,0xba,0xe9,0xc0,0x03,0x14,0x12,0x12,0x19,0x00,0x00,0x00,0x00,0x00,0x80,0x56,0x40,0x29,0x00,0x00,0x00,0x00,0x00,0x80,0x56,0xc0,0x52,0x03,0x6c,0x61,0x74,0x12,0x2b,0x0a,0x03,0x6c,0x6e,0x67,0x18,0x02,0x20,0x01,0x28,0x01,0x42,0x19,0xba,0xe9,0xc0,0x03,0x14,0x12,0x12,0x19,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0x40,0x29,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0xc0,0x52,0x03,0x6c,0x6e,0x67,0x42,0x0b,0x5a,0x09,0x2e,0x2f,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x62,0x06,0x70,0x72,0x6f,0x74,0x6f,0x33,}var(fileexampleprotorawDescOncesync。OncefileexampleprotorawDescDatafileexampleprotorawDesc)funcfileexampleprotorawDescGZIP()〔〕byte{fileexampleprotorawDescOnce。Do(func(){fileexampleprotorawDescDataprotoimpl。X。CompressGZIP(fileexampleprotorawDescData)})returnfileexampleprotorawDescData}varfileexampleprotomsgTypesmake(〔〕protoimpl。MessageInfo,2)varfileexampleprotogoTypes〔〕interface{}{(Person)(nil),0:examplepb。Person(PersonLocation)(nil),1:examplepb。Person。Location}varfileexampleprotodepIdxs〔〕int32{1,0:examplepb。Person。home:typenameexamplepb。Person。Location1,〔1:1〕isthesublistformethodoutputtype1,〔1:1〕isthesublistformethodinputtype1,〔1:1〕isthesublistforextensiontypename1,〔1:1〕isthesublistforextensionextendee0,〔0:1〕isthesublistforfieldtypename}funcinit(){fileexampleprotoinit()}funcfileexampleprotoinit(){ifFileexampleproto!nil{return}if!protoimpl。UnsafeEnabled{fileexampleprotomsgTypes〔0〕。Exporterfunc(vinterface{},iint)interface{}{switchv:v。(Person);i{case0:returnv。statecase1:returnv。sizeCachecase2:returnv。unknownFieldsdefault:returnnil}}fileexampleprotomsgTypes〔1〕。Exporterfunc(vinterface{},iint)interface{}{switchv:v。(PersonLocation);i{case0:returnv。statecase1:returnv。sizeCachecase2:returnv。unknownFieldsdefault:returnnil}}}typexstruct{}out:protoimpl。TypeBuilder{File:protoimpl。DescBuilder{GoPackagePath:reflect。TypeOf(x{})。PkgPath(),RawDescriptor:fileexampleprotorawDesc,NumEnums:0,NumMessages:2,NumExtensions:0,NumServices:0,},GoTypes:fileexampleprotogoTypes,DependencyIndexes:fileexampleprotodepIdxs,MessageInfos:fileexampleprotomsgTypes,}。Build()Fileexampleprotoout。FilefileexampleprotorawDescnilfileexampleprotogoTypesnilfileexampleprotodepIdxsnil}
  learnpgvgeneratedexampleexample。pb。validate。goCodegeneratedbyprotocgenvalidate。DONOTEDIT。source:example。protopackageexampleimport(byteserrorsfmtnetnetmailneturlregexpstringstimeunicodeutf8github。comgolangprotobufptypes)ensuretheimportsareusedvar(bytes。MinReaderrors。New()fmt。Printutf8。UTFMax(regexp。Regexp)(nil)(strings。Reader)(nil)net。IPv4lentime。Duration(0)(url。URL)(nil)(mail。Address)(nil)ptypes。DynamicAny{})ValidatechecksthefieldvaluesonPersonwiththerulesdefinedintheprotodefinitionforthismessage。Ifanyrulesareviolated,anerrorisreturned。func(mPerson)Validate()error{ifmnil{returnnil}ifm。GetId()999{returnPersonValidationError{field:Id,reason:valuemustbegreaterthan999,}}iferr:m。validateEmail(m。GetEmail());err!nil{returnPersonValidationError{field:Email,reason:valuemustbeavalidemailaddress,cause:err,}}iflen(m。GetName())256{returnPersonValidationError{field:Name,reason:valuelengthmustbeatmost256bytes,}}if!PersonNamePattern。MatchString(m。GetName()){returnPersonValidationError{field:Name,reason:valuedoesnotmatchregexpattern〔〔09〕AZaz〕(〔〔09〕AZaz〕),}}ifm。GetHome()nil{returnPersonValidationError{field:Home,reason:valueisrequired,}}ifv,ok:interface{}(m。GetHome())。(interface{Validate()error});ok{iferr:v。Validate();err!nil{returnPersonValidationError{field:Home,reason:embeddedmessagefailedvalidation,cause:err,}}}ifm。GetIds()0{returnPersonValidationError{field:Ids,reason:valuemustbegreaterthan0,}}ifval:m。GetAge();val0val120{returnPersonValidationError{field:Age,reason:valuemustbeinsiderange(0,120〕,}}if,ok:PersonCodeInLookup〔m。GetCode()〕;!ok{returnPersonValidationError{field:Code,reason:valuemustbeinlist〔123〕,}}if,ok:PersonScoreNotInLookup〔m。GetScore()〕;ok{returnPersonValidationError{field:Score,reason:valuemustnotbeinlist〔099。99〕,}}returnnil}func(mPerson)validateHostname(hoststring)error{s:strings。ToLower(strings。TrimSuffix(host,。))iflen(host)253{returnerrors。New(hostnamecannotexceed253characters)}for,part:rangestrings。Split(s,。){ifl:len(part);l0l63{returnerrors。New(hostnamepartmustbenonemptyandcannotexceed63characters)}ifpart〔0〕{returnerrors。New(hostnamepartscannotbeginwithhyphens)}ifpart〔len(part)1〕{returnerrors。New(hostnamepartscannotendwithhyphens)}for,r:rangepart{if(rarz)(r0r9)r!{returnfmt。Errorf(hostnamepartscanonlycontainalphanumericcharactersorhyphens,gotq,string(r))}}}returnnil}func(mPerson)validateEmail(addrstring)error{a,err:mail。ParseAddress(addr)iferr!nil{returnerr}addra。Addressiflen(addr)254{returnerrors。New(emailaddressescannotexceed254characters)}parts:strings。SplitN(addr,,2)iflen(parts〔0〕)64{returnerrors。New(emailaddresslocalphrasecannotexceed64characters)}returnm。validateHostname(parts〔1〕)}PersonValidationErroristhevalidationerrorreturnedbyPerson。Validateifthedesignatedconstraintsarentmet。typePersonValidationErrorstruct{fieldstringreasonstringcauseerrorkeybool}Fieldfunctionreturnsfieldvalue。func(ePersonValidationError)Field()string{returne。field}Reasonfunctionreturnsreasonvalue。func(ePersonValidationError)Reason()string{returne。reason}Causefunctionreturnscausevalue。func(ePersonValidationError)Cause()error{returne。cause}Keyfunctionreturnskeyvalue。func(ePersonValidationError)Key()bool{returne。key}ErrorNamereturnserrorname。func(ePersonValidationError)ErrorName()string{returnPersonValidationError}Errorsatisfiesthebuiltinerrorinterfacefunc(ePersonValidationError)Error()string{cause:ife。cause!nil{causefmt。Sprintf(causedby:v,e。cause)}key:ife。key{keykeyfor}returnfmt。Sprintf(invalidsPerson。s:ss,key,e。field,e。reason,cause)}varerrorPersonValidationError{}varinterface{Field()stringReason()stringKey()boolCause()errorErrorName()string}PersonValidationError{}varPersonNamePatternregexp。MustCompile(〔〔09〕AZaz〕(〔〔09〕AZaz〕)34;)varPersonCodeInLookupmap〔uint32〕struct{}{1:{},2:{},3:{},}varPersonScoreNotInLookupmap〔float32〕struct{}{0:{},99。99:{},}ValidatechecksthefieldvaluesonPersonLocationwiththerulesdefinedintheprotodefinitionforthismessage。Ifanyrulesareviolated,anerrorisreturned。func(mPersonLocation)Validate()error{ifmnil{returnnil}ifval:m。GetLat();val90val90{returnPersonLocationValidationError{field:Lat,reason:valuemustbeinsiderange〔90,90〕,}}ifval:m。GetLng();val180val180{returnPersonLocationValidationError{field:Lng,reason:valuemustbeinsiderange〔180,180〕,}}returnnil}PersonLocationValidationErroristhevalidationerrorreturnedbyPersonLocation。Validateifthedesignatedconstraintsarentmet。typePersonLocationValidationErrorstruct{fieldstringreasonstringcauseerrorkeybool}Fieldfunctionreturnsfieldvalue。func(ePersonLocationValidationError)Field()string{returne。field}Reasonfunctionreturnsreasonvalue。func(ePersonLocationValidationError)Reason()string{returne。reason}Causefunctionreturnscausevalue。func(ePersonLocationValidationError)Cause()error{returne。cause}Keyfunctionreturnskeyvalue。func(ePersonLocationValidationError)Key()bool{returne。key}ErrorNamereturnserrorname。func(ePersonLocationValidationError)ErrorName()string{returnPersonLocationValidationError}Errorsatisfiesthebuiltinerrorinterfacefunc(ePersonLocationValidationError)Error()string{cause:ife。cause!nil{causefmt。Sprintf(causedby:v,e。cause)}key:ife。key{keykeyfor}returnfmt。Sprintf(invalidsPersonLocation。s:ss,key,e。field,e。reason,cause)}varerrorPersonLocationValidationError{}varinterface{Field()stringReason()stringKey()boolCause()errorErrorName()string}PersonLocationValidationError{}
  然后我们就可以通过Validate方法来进行验证packagemainimport(fmt。learnpgvgeneratedexample)funcmain(){p:new(Person)err:p。Validate()err:Idmustbegreaterthan999fmt。Println(err)p。Id1000errp。Validate()err:Emailmustbeavalidemailaddressp。Emailexamplebufbuild。comerrp。Validate()err:Namemustmatchpattern〔ds〕(〔ds〕)39;p。NameProtocolBuffererrp。Validate()err:Homeisrequiredp。HomePersonLocation{Lat:37。7,Lng:999}errp。Validate()err:Home。Lngmustbewithin〔180,180〕p。Home。Lng122。4errp。Validate()err:nil}
  运行效果如下gorunmain。goinvalidPerson。Id:valuemustbegreaterthan999
  通过proto的注解扩展,配合这个插件,我们可以非常方便地实现参数校验能力,真正把idl当作交流沟通的完备工具,有效提升开发效率。〔(validate。rules)。uint32{in:〔1,2,3〕}〕;

七岁的小孩写硬笔书法,需要强调顿笔吗?不管是出于练字把字这漂亮还是追求书法的高度,都是一样重要的。顿笔是最基本的也是最重要的运笔技巧,如果没有这个,对掌握行书的节奏感,流动性,连贯意连很有影响。楷书就更不用说了,缺少顿如果有个三观不正的同学,学习目的是为了得到权利去做一些沦丧道德的事,并且学习努力让我感到恐惧该咋办?我操,小朋友,你要不想好好学习你就直说,别整这个。在家长面前扯这个都是没有用的。有事儿说事儿,不用这么拐弯抹角,你不想学了好好跟家长说,咱想办法找个出路。以后记住了啊,你就说你的事你在人生最低谷的时候是怎么熬过来的?生育女儿那两年,我没上班,老公却提出女儿一周岁之后,我们AA制,他负责奶粉钱,我负责房租果真,他说到做到,甚至没等到我领第一个月的工资,就实行了夫妻AA制从把女儿留守在老家,到拿到老师讲好自己的课,对调皮孩子不管,不问,不说,一切交给家长,万事大吉,你同意吗?作为一名老师,我战战兢兢的回答这个问题,有不当之处请各位朋友指正!现在的教育就是一台教师的独角戏,观众有学生,家长,领导和社会。教师要尽一切努力让所有的观众满意,任何一个观众都可以一年六部戏,两部爆红!番位高出王一博一截,黄轩怎么还是不火?大火首先有个条件,就是有突出能力,王一博舞跳的好,这是公认的,加上人帅,酷,颜值即王道,演技虽然不是强项,但是也不出戏,黄轩是演员,演技好,但是长相不突出,个人魅力差那么一点,所以刘泽一回归,浙江阵容再无短板,15项数据排前三,今年或登顶本赛季浙江队一路高歌猛进,排名始终排名第一,从来没有被超越,可以看出本赛季的浙江队真的太强了,由于刘泽一第三阶段前面一直没有出战,也有媒体说刘泽一受伤报销了,常规赛第38轮,刘泽一贝弗利詹姆斯在场上,球员们会是另一种心态威少表示赞同北京时间3月27日NBA常规赛迎来一场焦点大战,公牛在客场以118108击败湖人。公牛球员贝弗利赛后接受了媒体采访。当被问及之前在湖人效力时的感受,他说道是的,湖人那段经历很奇怪,上海这一夜,杨紫太美,虞书欣好辣,宋轶腰背绝,迪丽热巴赢麻了睽违两年,今年的微博之夜可谓是全面开花,格外隆重!半个娱乐圈的明星都齐聚上海,重工高定,PK比美,这么大个流量之夜,谁也不能撂挑子不是!一个明星少说也得有两三套造型,高定礼服都要被娱乐圈穿衣最露骨的这些女星,身材性感撩人,灼人眼球,太标致了头条创作挑战赛文阿明讲八卦编辑阿明讲八卦女明星职业的特殊性也就造就了她们敢穿的性格。在长年累月的高强度工作中,她们也渐渐对于穿衣方面带来的讨论变得不那么在意,只会穿能让她们变得更漂盛典造型哪家强?杨幂刘亦菲杨紫高圆圆唐嫣迪丽热巴头条创作挑战赛杨幂一袭红色长裙尽显妩媚优雅,身材曲线凹凸有致性感撩人,不愧是内娱85后顶流,这身材保持得也太好了。刘亦菲穿羽毛裙宛如山林里的孔雀公主,落落大方,优雅自信的姿态真的太为什么我的小孩初中数学成绩好,高中数学就一塌糊涂?是记住了,而非学会了,更不是会学了。父亲在世时讲过一个不是笑话的笑话。五三年小学六年级的算术课本上的一道例题印错,本地一学校的老师照本宣科,学生照单全收,升学考试全错赶巧试卷上就出
Netty学习七详解ByteBuf缓冲区头条创作挑战赛七详解ByteBuf缓冲区为了确保引用计数不会混乱,在Netty的业务处理器开发过程中,应该坚持一个原则retain和release方法应该结对使用。简单地说,在一个什么软件可以配音?哪个配音软件简单又好用?经验分享终于迎来了开年上班后的第一个周末,本想关掉手机好好睡一整天的。前女友突然转发了一个解说的视频给我,然后问这些解说声音是什么软件合成的万般无奈下,我找了十几个软件去测试,筛选出了5个小米13Ultra曝光活久见大改变!最便宜8Gen2再降价2699买吗声音小白12月努比亚发布了Z50,8128GB版2999元的起售价也是截至目前发布的首批骁龙8Gen2旗舰中最便宜的。没想到最近努比亚Z50开启了降价,再次刷新骁龙8Gen2旗舰的音响爱好者爱折腾是为了什么?作为一个音响爱好者,经常折腾这些玩意。家里其实不缺乏音箱功放,买现成的放在小仓库的架子上,想听才搬出来,品质也是够用的。可是每当有空的时候,或者是心血来潮的时候,总是爱折腾这些玩意特丽珑王者之剑德国AcapellaTheTriolonExcaliburMK5音箱原创赖英智新音响NewAudiophile对一家专注设计制造音箱的厂家来说,阿卡佩拉其实不常跨界。AcapellaAudioArts总公司位于德国西部重要工业城市杜伊斯堡(Duis张天爱带火了一种穿搭叫上面去运动,下面去约会,真显高级时尚既是多元的,也是包容的。当我们穿过大街小巷,总能看到不同风格的时尚穿搭。张天爱带火了一种穿搭叫上面去运动,下面去约会,真显高级。平时搭配总没思路的姐妹们,一起来学习一下张天爱的今年这种穿法火了袜子裹裤子,时髦又保暖,老寒腿的救星一年四季中十分常见的基础单品就属裤子了,不过看似基础的裤子,却非常考验穿搭功底,想要利用它打造出时髦潮流的造型,还真得花点心思。很多人习惯用一种款式的裤子穿过春夏秋冬,没有新意,实高圆圆身材这么好!不管正面看还是背后看,腰臀比都很惊艳很多女性随着年龄和身份的改变,打扮风格也随之发生变化。曾经的少女感和天真气质,逐渐在生活和岁月的打磨下发生变化,拥有更多层次的美感和韵味。在这一点,女明星也毫不例外。比如高圆圆,她眼霜篇(二)羽西雅诗兰黛兰蔻欧莱雅哪个才是最爱?昨天的一篇文章讲到的是眼霜对于我的重要性,仁者见仁,智者见智,不同的人有不同的观点,欢迎大家畅所欲言,发表自己的想法鼓掌鼓掌今天想继续聊聊眼霜的那些事!从大学毕业后,用了些小众眼霜TODS2023早春女士系列欣赏TODS2023早春女士系列慵懒与不羁同频呈演,TTimeless包袋的编织元素与T型金属饰扣巧妙结合,赋予整体造型极具假日感的惬意悠闲。TODS2023早春女士系列践行都市实用主受男生喜爱的女生穿着颜色竟然不是白色和粉色?对于女性来讲,白色和粉色的衣服是很常见的女性服装的颜色,喜欢穿这两个颜色的女生也很多,但是从男生角度来看,穿这两种颜色衣服的女生是不是最受欢迎呢?近日,日本专家就对这个问题进行了研
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网