yinzhuoei_seho 发布的文章

复合类型

顾名思义, 复合类型就是其他类型组合而成的, 最典型的就是结构体struct和枚举enum.

字符串

rust中的字符串和我们平时说了解到的编程语言不一样, 比如下面这一段代码是会编译错误的:

fn main() {
  let my_name = "Pascal";
  greet(my_name);
}

fn greet(name: String) {
  println!("Hello, {}!", name);
}

切片

切片在go中就已经很流行了, 它允许你引用集合部分内容, 而不是全部, 在字符串中, 我们可以这么写:

let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];

如果是从0开始, 就可以省略0:

let hello = &s[..5];

同理, 如果你要截取到尾部, 你可以这样省略:

let hello = &s[1..];

但是如果我们操作中文, 就需要格外注意utf-8啦, 一个中文是3个字节, 所以我们在做切片的时候, 如果切到第二个, 就会编译器报错:

实际上, 如果返回切片, 其实是一个字符串引用, 所以我们可以写出这样一段代码:

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);
}
fn first_word(s: &String) -> &str {
    &s[..1]
}

不仅仅字符串可以进行切片, 数组也是可以的:

let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);

如果我们通过字符串字面量创建字符串的话, 是这样的:

let a = "hello";

此时a就是&str类型, 我们完全可以这样编写代码, 因为此时a指向了可执行文件中的某个点, 也因此字面量创建的字符串是不可变的, 因为&str就是不可变的.

let a: &str = "hello";

字符串是什么

rust中的字符是由unicode编码实现的, 每一个字符占据了4bytes, 但是字符串是用utf-8实现的, 占用的字节数是1-4变化的, 所以更节省内存.

&str和String的区别

在语言层面上来说, 只有str一种类型, 是硬编码到可执行文件中的, 无法被修改; 但是在标准库中我们却可以使用String来创建一个不定长度的字符串类型; String同样也是utf-8编码也具有所有权特性;

如何互相转换

str → string

let a = String::from("hello world");
let b = "hello world".to_string();

string → str

fn main() {
    let s = String::from("hello,world!");
    say_hello(&s);
    say_hello(&s[..]);
    say_hello(s.as_str());
}

fn say_hello(s: &str) {
    println!("{}",s);
}

字符串索引

在js中, 我们可以使用索引轻松的访问字符串, 但是在rust中这是不被允许的:

let s1 = String::from("hello");
let h = s1[0];

因为字符串的底层是使用[u8]字符数组实现的, 如果我们在字符串中使用中文, 一般一个中文是3个byte, 那么此时我们操作中文字符串时, 可能会得到预想不到的值; 所以在rust中, 字符串索引是一个容易造成误解的功能, 因此不支持;

如何正确操作utf-8字符串

如果你想要通过unicode方式操作字符串, 就可以使用.chars()函数

for c in "中国人".chars() {
    println!("{}", c);
}

如果你想要查看字符串在底层的字节数组, 就可以使用bytes()函数

for b in "中国人".bytes() {
    println!("{}", b);
}

228
184
173
229
155
189
228
186
186

ps: 如果要在rust中截取正确的子串, 就要使用一些库, 比如utf8_slice

深入理解字符串

为什么string可变而str不可变呢? 这很容易理解因为str是在我们编译期间就可以知道的内容, 即不可变, 直接编译到可执行文件中; 但是我们在开发中, 不可能都使用不可变的str, 通常我们的值都会在运行时经过逻辑处理得到的, 所以我们需要一个可变的string类型; 可变的string类型是要在堆上划分一块区域存储的, 等到需要被释放时才会归还给操作系统, 整个周期都是在运行时;

元组

元组是由多种类型组合一起形成的, 它的长度是固定的, 顺序也是固定的; 我们可以通过这个函数创建一个元组:

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}

可以用模式匹配来解构元组

let (x, y, z) = tup;

也可以通过.索引的方式来获取元组元素

tup.1

在函数中, 如果要返回多个值, 除了使用下面即将介绍的结构体之外, 还可以使用元组

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)
}

结构体

在元组的介绍中, 返回的calculate_length函数是一个元组类型, 这对于程序来说是不好维护的, 因为不清楚返回参数的任何意义; 那么rust中有一个复合类型叫做结构体可以解决; 那么在其他语言中结构体可以当作object, record(typescript); 结构体是由多个类型组合而成; 它可以给每个类型设置一个名称(key), 所以结构体对比元组更加灵活

我们定义一个结构体, 非常简单:

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

我们需要使用这个结构体构造一个实例, 就更简单啦:

let user1 = User {
      email: String::from("someone@example.com"),
      username: String::from("someusername123"),
      active: true,
      sign_in_count: 1,
  };

和ts一样, 我们定义的结构体需要完全初始化, 即数据模型要和结构体完全匹配.

如果我们需要修改user1的某个字段, 必须把整个user1变为mut可变类型, 结构体不支持仅把某个元素变为可变:

user1.email = String::from("anotheremail@example.com");

我们在结构体中, 对于同名的key和value是可以做到省略简写的, 比如这样:

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}

同样的, 我们在ts中经常使用es的扩张运算符来更新对象, 在rust中, 你完全可以使用类似的语法更新结构体 (必须写在尾部)

let user2 = User {
    email: String::from("another@example.com"),
    ..user1
};

关于更新语句, 所有权也需要关注, 在rust所有权中, 部分类型如果支持copy, 那么数据在这里就会被拷贝, 比如bool和u64都实现了copy, 那么在此时的更新结构体的语句中, 仅仅只是把值copy了一份而已; 但是username是string类型, 在此处是转移了所有权到user2中, 那么在user1中就不能操作username了.

结构体不仅仅有key, value这种形式, 还可以有其他形式

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

枚举

枚举是一个类型, 有多个枚举成员, 枚举值是其中某个枚举成员的实例

enum PokerSuit {
  Clubs,
  Spades,
  Diamonds,
  Hearts,
}

在一些特殊场景下, 你不仅仅可以指定成员类型, 还可以代替结构体简化代码: 在ts中枚举是运行时类型(经过编译器编译之后为对象), 但是在rust中就是实打实的类型, 不能在声时指定值;

如果使用传统的结构体, 是这样写的

enum PokerSuit {
    Clubs,
    Spades,
    Diamonds,
    Hearts,
}

struct PokerCard {
    suit: PokerSuit,
    value: u8
}

fn main() {
   let c1 = PokerCard {
       suit: PokerSuit::Clubs,
       value: 1,
   };
   let c2 = PokerCard {
       suit: PokerSuit::Diamonds,
       value: 12,
   };
}

我们通过枚举进行改造, 可以大大简化代码:

enum PokerCard {
    Clubs(u8),
    Spades(u8),
    Diamonds(u8),
    Hearts(u8),
}

fn main() {
   let c1 = PokerCard::Spades(5);
   let c2 = PokerCard::Diamonds(13);
}

指定成员类型

enum PokerCard {
    Clubs(u8),
    Spades(u8),
    Diamonds(char),
    Hearts(char),
}

更复杂的枚举成员类型 (结构体)

struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}

相比较元组结构体, 从语法角度上来说枚举的方式更为简洁且高内聚

Option

在rust中避免了使用大多数语言经常用到的null概念, 改为option, 其类型本身就是一个枚举

enum Option<T> {
    Some(T),
    None,
}

some指的是有值(任意值), 类型为t, t是一个泛型参数; none则为空

值得注意的是, option并不需要显式的引入, 因为它本身就被包含在标准库中, 也不需要::调用some和none;

let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;

在rust语言设计中, 你如果想使用类似null的概念, 就必须告诉编译器这个null如果有值的话是什么类型, 即第三段代码; 反之如果使用了some, 就代表了值存在于some之中; 那rust为何这么做, 多此一举新增一个option枚举呢?

其实主要核心问题还是安全性, rust编译器要在编译器确保数据的安全, 不能因为null的滥用导致程序错误, 如果不使用option来标记可能为空的值, 那么在之后的代码中你可能就会忘记这个值的类型和其他类型做逻辑运算, 那么此时null就会被爆雷; 所以如果使用option标记值, 在编译期就可以让rust判断, 提醒开发者.

数组

数组很简单, 同样rust可以设置数组的类型

fn main() {
    let a = [1, 2, 3, 4, 5];
        // 这里的类型声明, ;之前是类型, ;之后是重复几次
        let b: [i32; 5] = [1, 2, 3, 4, 5];
        // 同样的也可以通过上述的语法, 让我们初始化数组更快速, 初始化值为3, 重复5次
        let c = [3; 5];
}

访问数组

a[0]

可以进行切片

let slice: &[i32] = &a[1..3];

最近学习rust的时候,了解到rust的浮点数实现是和js是一样的, 也就导致了我们在js上遇到的精度问题, 在rust同样也能遇到.

首先我们来理清, rust的默认浮点类型是f64, 而js由于和其他语言不同, 无论是整数和浮点数都是number类型, 也是64位固定长度, 也就是标准的双精度浮点数,

双精度浮点数(double)是计算机使用的一种数据类型,使用 64 位(8字节) 来存储一个浮点数。 它可以表示十进制的15或16位有效数字,其可以表示的数字的绝对值范围大约是:-1.79E+308 ~ +1.79E+308 [1] 。

既然2种语言底层的标准都是一样的, 都是使用了IEEE 754标准中的double精度, 那我们就直接使用大家熟悉的js来做demo.

为什么使用double精度标准

对比单精度标准来说, 虽然double精度占用比单精度高(8byte > 4byte), 这也就间接意味着cpu在处理上, 单精度会有优势, 但是单精度的致命缺陷就是有效数少而且范围也会更小, 总的来说适用性略低, 而且在现代cpu来说, 处理速度上基本是可以忽略不计的.所以在rust中默认的浮点数类型就是f64, 如果有需要就选择f32(单精度)

double精度如何存储

直接从wiki上抄一张图下来

618px-IEEE_754_Double_Floating_Point_Format.svg.png

  • 符号位:1 位 (+, -)
  • 指数:11 位 (次方)
  • 有效位数精度:52 位

运算过程

我们通常会用十进制来表达浮点数, 但是我们rust/js底层都是用二进制实现浮点数类型的, 比如说我们写一句这样的代码:

var a = 0.1;

在我们程序员眼中它可能就是绝对等于0.1的, 但是在内部实现中, 它需要转换为二进制, 但是在二进制中就是无限精度类型, 也就变成了下面这样:

0.1 -> 0.0001 1001 1001 1001...(1100循环)

但是由于我们底层的标准, 有效位数的精度是52位, 我们在做浮点运算的时候, 多余的数字都会被截断, 所以在js从二进制转换为十进制之后, 就不是我们预想的答案了(在一定精度结果是对的)
, 同理在rust/js中我们也不要使用浮点数做比较, 因为是一个危险不受信赖的计算结果, 也希望精度问题能够引起大家重视, 因为有很多危险的事件是由转换精度触发的:

对于Ariane 4火箭的工作代码在Ariane 5中被重新使用,但是Ariane 5更高速的运算引擎在火箭航天计算机中的算法程序中触发了一个bug。该错误存在于将64位浮点数转换为16位带符号整数的程序中。更快的运算引擎导致了Ariane 5中的64位数据要比Ariane 4中更长,直接诱发了溢出条件,最终导致了航天计算机的崩溃。首先501航天飞机的备份计算机崩溃,然后0.05秒之后,主计算机也崩溃了。这些计算机崩溃直接导致了火箭的主要处理器使火箭的运算引擎过载,同时导致火箭在发射40秒后解体破碎。

顺带提一句, rust中对于整型有溢出处理, 在release环境下, 会按照补码循环溢出的规则去解决, 但是这仍然会造成结果不一致的错误.

如何解决

rust: 我不知道咋解决, 我才学rust
js: 大把的精度库, 最流行的方案就是底层使用string了, bignumber.js, 就可以避免浮点数陷阱;

基础类型

rust是一门静态编程语言, 所以我们有必要知道它的类型, rust的类型可以分为基本类型和复合类型(也可以称之为复杂类型), 基本类型指的就是原子化最小的类型, 它不能转换为其他类型;

rust不像ts, ts是js的超集, ts可以更好的推断类型, 但是rust拥有一个很聪明的编译器, 你可以无需指定类型, 让编译器去自动推断, 但是某些情况下编译器无法推断类型, 比如这样

let guess = "42".parse().expect("Not a number!");

鬼知道guess是什么类型, 所以编译器会报错, 你只需要显式的指定类型即可;

数值类型

rust创建数值非常简单

let a = 1;

整数

我们继续来探讨整数类型, 我们之前了解过的i32类型, 表示有符号的32位整数

i表示integer, 与之相反的是u, 代表无符号

类型统一定义为 “有无符号” + “位数(bit)”, 无符号表示就是正数, 有符号就是正负; 简单的使用准则需要我们记住, rust整形默认使用i32, 可以首选i32, 而且性能也是最好的;

我们在处理整型的时候, 如果设置的值超过了范围, 那么rust会区分模式, 做不同的决策, 比如在debug模式中, 程序会报错退出; 如果是release环境, 会被补码为范围内的最小值, 因此这样的结果是不符合预期的, 会被认为是错误的.

浮点数

浮点数默认类型是f64, 但是rust有一个浮点数的陷阱, 我们通常会使用十进制表达浮点数, 但是rust底层是使用二进制实现浮点数类型的, 比如说0.5在十进制上存在精确表达, 但是在二进制中不存在, 所以就会造成歧义, 所以想要表达完整的真实浮点数字, 就必须使用无限精度的浮点数才行.

还有一个注意的点就是, 我们不要对浮点进行比较, 这和js一样, 由于rust的浮点类型底层是二进制, 而js同样在浮点数运算时也是二进制, 都会存在不准确的问题; 在rust中对浮点数进行比较的时候, float声明了PartialEq, 注意它不是Eq; 在map数据结构中的k类型, rust是需要你传入声明过Eq 的类型, 很显然float不满足要求; 而且当我们使用浮点做比较的时候, 会造成编译器错误.

NaN

和js一样, 我们可以在rust中做一个防御性编程:

fn main() {
    let x = (-42.0_f32).sqrt();
    if x.is_nan() {
        println!("未定义的数学行为")
    }
}

序列

rust提供了一种简洁的方式生成连续的数值

// 生成1-5 (包括5)
1..=5
// 生成1-5 (不包括5)
1..5

字符, 布尔, 单元类型

这一部分比较简单,

char

fn main() {
    let c = 'z';
    let z = 'ℤ';
    let g = '国';
    let heart_eyed_cat = 'hhh';
}

不管是ascii, 还是unicloud都算作rust字符char; 另外字符是用’’包裹的, “”是表达为字符串

bool

rust中的布尔类型和其他语言一样, 存在true/false

单元类型

0长度的元组, 单元类型使用()来表达, 我们可以用单元类型占位, 它不占用任何内存, rust函数中的main还有print函数都会返回一个单元类型. 我们不能说main函数没有返回值, 因为没有返回值在rust中是有单独的定义的(发散函数: diverge function) , 顾名思义, 无法收敛的函数.

语句和表达式

在rust的函数体中是一系列语句组成, 最后是由表达式返回, 比如这样

fn add(x: i32, y: i32) -> i32 {
    let x = x + 2; // 语句
    let y = y + 3; // 语句
    x + y // 表达式
}

语句

 let x = x + 2; // 语句
 let y = y + 3; // 语句

由于let是语句, 我们不能将let赋值给其他值:

let b = (let a = 8);

这样编译器会报错…

表达式

表达式会进行运算/求值, 比如1+2, 会返回3, 我们在语句上面写了这段代码:

 let x = x + 2; 

这里的x + 2确实是一个表达式, 只要记住只要能返回值, 它就是表达式 而且表达式不能包含分号, 比如下面一段代码

let y = {
    let x = 3;
    x + 1
};

如果x + 1包含了分号, 那么此时这个语句块不会返回任何值了, 也就不算作表达式了, 所以我们在rust中编写函数的时候, 如果要返回值, 就要注意这里不需要加分号;

函数

rust的函数很简单, 下面是一个例子, 有关键字, 函数名称, 形参名称和类型, 函数返回值类型, 以及一个代码块, 就构成了一个最简单的函数:

fn add(i: i32, j: i32) -> i32 {
   i + j
 }
  1. 首先rust是强类型的语言, 我们在编写函数的时候, 参数的类型是必须的, 如果不提供参数的类型是会报错的.
  2. 函数的返回值就是代码块的最后一行的表达式返回值, 当然我们也可以使用return关键字提前返回也可以
  3. 在单元类型中, 我们提到了无返回值, 我们可以使用单元类型作为返回, 而一些表达式你不幸加了分号变成了语句, 那么此时也会返回一个单元类型.
  4. 在上文提到了diverge function, 我们可以使用!作为函数返回类型, 这一般会作为程序崩溃的函数, 代表永不返回:
fn end() -> ! {
  panic!("it is over...");
}

首先, 我们作为程序员想要学习一个新东西是非常简单的, 尤其是我们熟悉的互联网领域, 我们通常接触的知识面是其他的互联网同僚们要很久才能接触到的, 是因为“信息差”这个有趣的东西; 那我的女朋友想0基础学习ui设计的话, 那我肯定到了最拿手的事情了, 作为一名老前端开发, 我和设计师的沟通(battle)是在日常工作中最多的, 所以这篇文章我会自己梳理学习ui设计的思路以及ui概念, 再到互联网企业中的ui设计到底需要会什么, 还有大家非常关心的薪资情况, 希望各位设计师读者多多指教哈~

认识一下这个职位是什么

很多人对ui,ux这些名词太陌生了, 所以通常都会造成一些误解,会认为ui/ux设计师就和装潢设计师一样需要下工地去做工程图, 就像外界对于程序员的看法都是“黑客”, “盗号”, “格子衫”一样. 所以无论是我们设计新手如何理解ui/ux概念还是如何向外行人解释这个职位, 我们都需要彻底了解职位本质, 我觉得这非常重要, 至少是比学习软件更重要.

UI

ui指的是(user interface), 程序员表示看到interface就不困了, 意思是用户+界面, 你可以简单理解为使用者(人)和界面(产品)之间用来沟通的, 其实在很早以前也有类似的知识(即广义上的ui), 只不过它们都不是电子产品/屏幕, 它们被称之为“人体工学”, 人体工学的核心理念就是使用者(人)和机器/环境的交互/沟通学科; 所以细细想想它们还是蛮相近的; 二战时期中战斗机的驾驶舱的操控设计, 通常都是把所有的按钮直接怼到你面前,有时因为飞行员的误操作造成了很多的空难意外, 人们也慢慢意识到用户和机器是需要更流畅更便利的交流, 所以才诞生了人体工学的学科概念, 那发展到现代, 我们往往接触的都是电子设备, 使用到的网站/app/系统应用也和人体工学一样需要有更好的交流, 这就是ui设计师的职责.

UX

ux指的是(user experience)用户经验/体验, 我个人会认为“体验”更贴切一点; 在大多数你能看到的企业的招聘需求中会把ui和ux放在一起讨论, ui&ux设计代表了设计师需要把流程和外观都要调整到最符合特定用户, 从前端工程师的角度出发, ux可以单纯的指动画/手势/字体/布局/跳转等等, 是需要研究特定人群才能得出的设计论, 而不是埋头苦干地做图. 在一些大型企业中, 你可能会看到专门招聘ux的岗位, 在这种岗位通常都会需要你具备: 研究用户心理, 分析产品易用性等等, 所以对于外观设计(ui)的要求不是那么高.

如何选择

如果你更偏向设计出nice的界面, 而不是专门研究用户心理, 分析产品等等, 你就可以选择ui这个方向了, 但是一个优秀的ui设计师是需要同时具备基础的ux能力的, 那么反之你不想去关心界面喜欢研究用户行为而且不愁就业问题, 那么你可以专心研究ux方向;

互联网团队的基础结构构成

如果你是一个还没入互联网圈子的朋友, 那么你大概率还不了解设计师在团队主要担任什么角色, 那么这个部分我就简要地概括一下团队构成, 让你有一个大概的认识吧. 首先一个互联网产品, 我们就以一个app来举例, 是需要分为需求方和产出方的, 需求方(甲方)一般是我们的老板和上级, 他们会规定app的大需求方向以及业务场景;

比如沈老板说: “我们下一个季度要开发一个应用, 名字就叫[小绿书], 照着小红书抄就可以了”

这个时候团队中会有一个产品经理(PM), 来整理老板的需求和方向, 并且产出文字性/图形化的东西, 用来给设计和开发表达需求; 产品经理这一步非常关键, 他所产出的东西必须要和老板的需求足够贴合, 并且得到老板的认可, 因为如果不这样, 开发和设计都会按照产品经理的错误产出进行研发, 会导致团队项目停滞崩溃;

产品经理小刘说: “老板, 收到, 我的需求已经和你确认过了, 那我就去和设计和开发同学开会了”

我们的设计师角色会根据产品的产出, 设计app的ui界面, 并且关联每个页面(比如a页面要跳转到b页面), 当然设计师并不是直接上手设计的, 通常他们都会调研背景, 适用人群以及竞品的方案, 会设计多个版本的ui和产品/老板进行交流协调, 最终拍板决定之后, 这个设计稿才会到我们的开发同学这里了.

设计师小蕾说: “昊哥, 我在figma (一个ui设计协作工具) 已经把ui确定了, 你们现在可以开发了”

这个时候前端同学昊哥拿到设计师提供的ui设计稿之后, 就吭哧吭哧进行开发啦, 这个时候会有一个角色叫做后端, 那么前端和后端是开发环节中最核心的部分, 前端负责把设计稿还原成代码而且负责和后端进行交互, 让app能够被使用 (被使用的意思就是可以登陆, 点赞, 评论), 那么登陆, 点赞, 评论的服务实现代码就是由后端同学完成的.

我们文章标题所说的“全栈工程师”广义上指的就是同时掌握多种技术的开发工程师 (技能不限于前端后端), 开发同学写完代码之后, 会由测试工程师进行质检, 在质检期间会发生很多很多“bug”, 所以测试工程师往往要和前后端进行协调改进产品, 最后一个被检验合格的app小绿书就正式上线了!

我们来梳理一下, 一个最基础的互联网团队的闭环:

老板(甲方) -> 产品经理 -> 设计师 -> 前端同学 -> 后端同学 -> 测试同学

学习什么设计工具

在这个部分, 仅仅代表我个人的看法, 学什么工具并没有什么鄙视链, 你需要结合你想工作的城市用人需求以及你的电脑系统. 我们简单梳理一下几款流行的设计软件:

  1. ps (懂得都懂, 如果你是windows用户, 那么ps将会成为你的设计必修课)
  2. sketch (音译: 死开吃) (如果你是mac用户, sketch就是你的必修课)
  3. figma (音译: 飞格马) (它是一个独立的设计工具, 也是目前世界最新潮的设计平台, 被国内外很多大厂投入使用, 最重要的是它不会在意你的电脑是windows/macos)
  4. mastergo (音译: 马死特儿狗) (它是一个类似figma的国产工具, 也是今年刚刚上线不久的, 在国外技术垄断的情况下, 如果你喜欢figma但是因为种种原因不能使用, 那么它也是一个非常好的选择)
  5. ae (选修且难度颇高)
  6. c4d (选修且难度颇高)

个人建议: 无脑选择figma, 因为figma和sketch很像, 你可以做到学一个通二个, ps你可以作为选修

要使用什么电脑

在知乎和各大论坛上, 程序员群体常常会因为是使用macos还是windows电脑而有很多讨论, 那么设计师群体我是真的没见到过.
请无脑选择macos (优先m1芯片-macbook pro), 不要选择屏幕大的mac笔记本, 因为公司肯定有外接显示器/公司土豪会给你准备一个imac, 那玩意屏幕大
如果你学习figma, 在学习期间, 你没有必要买一个mac电脑, 但是为了以后你的职业发展, 你以后的主力设计机器一定要是mac (让公司花钱, 自己花那钱干嘛)

想学设计的女同学千万不要误解了, 这个是mac苹果电脑, 可不是口红品牌啊

如何自学

如果你看我这篇文章之前, 有想过自己报班学习, 那么请你看完以后不要有这样的想法了; 报个班2/3w, 都够你买3个mac笔记本了, 你就把你手机上的游戏抖音卸载了, 好好自学个一年半载, 懂了吧, 这个板块就给你讲如何自学的, 我自身是程序员, 但是道理都是一样的, 我不指望和我一样6点起床学一天, 你就每天花2,3小时每天学一下, 完全就够了.

习惯

你需要保持几个好习惯, 在最初学习设计时, 我们首先要定期浏览设计咨询和文章, 来源的地方有很多, 除了我们熟知的知乎, 站酷, 优设, bilibili, (别以为我会提花瓣和千图, 这几个平台少看)等国内平台, 我们仍然需要关注几个国内外的平台 (有的打开会很慢, 有条件的同学可以翻墙上外网, 外网很有必要, 可以获得第一手资料):

  1. https://dribbble.com/ 看完灵感爆棚
  2. https://www.pinterest.com/ 配图绝了
  3. https://www.behance.net/ 超级有设计感的图集网站
  4. https://www.feeeedin.com 国内的设计资讯聚合, 一站式预览
  5. http://www.webdesignfile.com/ 一些优秀的网站设计
  6. https://muuuuu.org/ 同上
  7. https://siiimple.com/ 同上
  8. https://ui8.net/ 同上
  9. https://miro.com/signup/ 同上

设计同学要和前端同学打交道, 所以我们也有必要了解一下开发同学的组件库, 即阿里, 腾讯等大厂的设计规范(主要面向程序员), ui同学过个眼熟就行

  1. https://ant.design/components/button-cn/ 阿里的antdesign组件库
  2. https://youzan.github.io/vant/#/zh-CN/button 有赞的vant组件库, 移动端顶呱呱
  3. https://semi.design/zh-CN 抖音的semi组件库, 够新够酷

作为前端, 我筛选了3个你需要了解的组件库, 那么同样的, 你还需要了解一些图标组件/规范, 这一类的设计规范有很多, 我就列举一个国内最好的:

  1. https://www.iconfont.cn/

同样的, 还有字体规范, 我们在设计中需要很多特殊的字体, 就可以到这里去下载, 也是国内最好用的字体平台:

  1. https://www.hellofont.cn/

我们提供了这么多的链接, 就是想要教会你如何去获取资源, 在有外网的条件下, 你完全可以去更牛逼的平台获得最新的潮流资讯, 拿到第一手信息, 获得信息差, 提高行业竞争力. 我们只需要每天花半个小时, 把这些平台逛一逛, 文章读一读, 如果你有多余的精力, 完全可以把新东西用在你的作品中, 并且进行总结在社区发表文章, 这可以提高你的社区影响力 (和程序员一样)

视频资源

ohhh, 这就很值得考究了, 通常我们学习ui设计, 我们要多半学习软件的操作, 这也是培训班会教你的东西, 他们不会培养你的审美感, 大多数都只会教给你软件的使用方法. 那么在看这部分内容之前, 我相信你已经心中有数, 要学哪个软件了, 我就以figma为例, 给大家简单推荐几个教程作为入门.

  1. https://space.bilibili.com/15741969/channel/collectiondetail?sid=255058 b站搜像素范figma
  2. https://space.bilibili.com/108104104 b站挺火的figma宝藏up主

除了软件的教学, 我也希望你能观看一些著名设计师的演讲/公开课, 那么这些资源你可以在极客时间/掘金/知乎/优设中找到, 尤其在优设中你可以看到很多大厂的设计师分享的各种习惯, 尽管我觉得没多大用对于新手, 但是也能让你多少学一点东西.

书籍推荐

和程序员一样, ui设计师同样需要阅读一些著作, 这些著作不会短时间的提高你的设计水平, 而是会陪伴你的职业生涯, 是你之后迈向更高层级的资本

  1. ui设计黄金法则
  2. 大话设计师
  3. 腾讯传

如何高效率的自学

这个部分和ui设计没有关系, 我会推荐我在学习编程时, 把我觉得好用的工具链和习惯分享给你

  1. notion (笔记软件, 超高颜值且免费, 如果你是外网环境请优先使用它作为笔记软件)
  2. 印象笔记/wolai/语雀/腾讯文档 (wolai是notion的国内替代品, 如果你没有外网就可以考虑使用wolai)
  3. 所有的视频资源请第一时间去youtube上查询, 因为youtube的视频质量往往会比较高
  4. 避免使用百度, 请使用谷歌, 并且关键字检索时, 尽量避免使用中文 (你需要学到最国际化的设计理念, 而不是二手的国内知识)
  5. 你需要一个严格的作息时间, 即每天几点到几点是学习时间, 这个时候谁也不能打扰你, 也不要做转移注意力的事情, 比如刷抖音/小红书
  6. 尽量早睡早起, 早上5 6点起床是大脑非常清醒的, 只要你睡的够早, 就可以把晚上低效率的时间挪到早上
  7. 你需要分类你的浏览器标签, 把你每天所看到的有趣的, 添加到不同领域中
  8. 你要善于产出, 不管是视频还是文章, 无论你的好坏, 你都可以发布到自己的博客/朋友圈/其他设计平台, 便于纠错, 营造成就感, 让别人给你查漏补缺
  9. 作为设计师新手不像程序员, 要做很多很多项目, 其实不然, 你要做的就是接触更多领域的设计规范, 你可以去参加比赛, 或者接外包快速提高自己的水平, 不一定非要一个完整的项目
  10. 尝试加入一些小圈子, 比如互联网程序员圈子, 设计师圈子, 乱七八糟的群多加一点, 这样你有各方面的问题, 都有渠道去解决, 同理你也可以把你的疑惑发布到社区中

推荐时间表

  1. 19:00 - 22:00 学习figma软件, 并且产出笔记
  2. 6:00 - 7:00 你可以阅读一些书籍
  3. 12:00 - 13:00 浏览一下最新的技术资讯
  4. 15:00 - 18:00 将昨天晚上学习的笔记和阅读的书籍所结合, 多做几个demo, 给自己几个主题 (也可以做比赛的主题, 比赛优设一大堆, 随便参加)

除此之外, 如果你有空余精力的话, 请在地铁, 公交, 空闲时刻去刷资讯, 比较方便的话还是优设, 里面的文章质量还真的不错

关于卷

别听TM任何一个人看你学习, 就说你卷, 我特别不喜欢这个词, 你就学你自己的, 都是为了以后未来, 咋没人说考研人, 考公人卷, 都是一些老傻逼双标人了, 不要理他们. 更何况你是0基础学习ui设计, 你需要一个干净轻松的自学环境, 不要被周围的环境影响了, 如果你坚持不下去, 就可以去报班去学习ui设计; 我的很多朋友都是从编程培训班出来的, 我也或多或少听说过一些, 有些培训班的环境很差很差, 可能不仅不会帮助你建立氛围, 还会影响你的心智 (抱着娃来学ui设计你敢信, 销售小姐姐也在学, 所以竞争蛮大的).

就业情况

互联网行业的各个岗位都是处于半饱和状态, 而且今年的形势不容乐观, 在这个部分我会简单介绍西安的就业情况, 如果你想着重了解一线城市的薪资, 那就在这个西安的基础上加5k-8k, 可以供你参考. 设计行业不像程序员看中学历和学校, 相反会看中你的工作年限和技术能力, 所以我觉得对于学历不是那么好的同学是一个很大的好处, 除了大厂的ui设计师是有严格的学历要求(统招本科/硕士等), 在普遍的企业中基本没有这样的要求; 而且个人觉得大厂的员工并没有比其他非大厂的员工高人一等, 甚至大厂的某些部门做的业务是很差很差的, 所以希望刚刚入门学习设计的同学不要好高骛远, 也不要过度的追求大厂岗位, 提高自己的硬实力才是最重要的.

哪所城市

个人推荐几个还不错的城市(排名不分先后):

  1. 苏州
  2. 杭州
  3. 南京
  4. 成都
  5. 重庆
  6. 西安

薪资问题

以西安举例子, 也结合了一些设计师朋友给的建议, 给出了一个可参考的薪资范围, 在给定一个学历(大专-硕士)硬性条件之下, 有了下面这个表格:

  1. 在校实习生 (2-3k)
  2. 一年工作经验 (4-6k)
  3. 二年工作经验 (7-8k)
  4. 三年工作经验 (10-15k)

在西安的设计行业, 15k+是很难达到的, 除非你进大厂或者干到设计总监.
但是不可否认的是如果你能力特别突出, 是肯定可以突破这个薪资范围滴, 而且我们需要在工作期间尽可能的保持每天学习, 仅仅会一个技能是不够的, 你需要同时提高你的审美水平, 其他软件的技能, 以及硬实力和软实力.

招聘jd中的技能树

  1. figma, ai, ps
  2. 有些公司会让你有可视化大屏的设计经验 (这玩意西安老火了)
  3. 设计思路良好, 基本功扎实
  4. 有些傻逼公司会让你掌握html,css,js(前端知识), 要小心让你去写代码, 慎重
  5. 3dmax加分项
  6. c4d加分项
  7. ae加分项

如何挑选好的实习岗位

如果你是在西安的一本二本普通大学, 请不要相信学校承诺的包就业, 2022年了就别信这一套了, 咱们就自己多学点提前找, 不要等着快毕业才开始学开始找, 那就完蛋了, 晓得吧. 你走学校的校招也是个人比较推荐的, 但是通常我会建议同学们在校招之前自己去外面公司面试, 因为有3个好处:

  1. 有更多的面试经验
  2. 有更好的工作机会
  3. 可以提前知道自己值多少价

那么如何挑选公司呢, 你就记住以下的公式就可以了:

大厂 > 自主创业公司 > 大外包公司 (西安中软等这一类的) -> 小外包公司

  1. 去大厂之前先要询问做什么产品, 什么部门, 一个大厂履历对你以后职业生涯很有帮助
  2. 自主创业公司指的就是自己独立的产品, 无论公司大小, 只要你认为是不错的产品, 就值得一去
  3. 大外包公司, 项目很多, 加班基本都很多, 通常一个做完就下一个继续做, 和电子厂没区别, 有些公司福利也不好
  4. 小外包公司, 通常不仅有大外包公司的所有毛病, 还比不上大外包的福利, 去个锤子?

作为一个新人, 只要不倒贴钱, 建议不要太在意薪资, 只要不是太夸张, 我毕业第一份工作就是1.2k(非实习), 干几个月就跳槽不就得了.

面试须知

在面试的时候, 你不仅需要提前做好表达和简历, 还要准备一份精美的作品集, 用于展示你的能力. 此时你就需要挑选你之前做的demo/项目/比赛作品, 关于作品集, 我这里就不推荐了, 因为我也没做过, 但是网上有很多范本, 集中在优设/站酷等网站, 它们会告诉你怎样设计作品集

  1. 请不要编造简历, 这是不诚信的行为, 尤其是编造年龄/工作经验, 要不然试用期3个月你就每天活在胆战心惊中
  2. 面试要自信, 你和面试官是平等的, 不要唯唯诺诺恳求
  3. 记得真诚的要面试反馈, 如果好的面试官, 会给你下一步的方向, 还是很不错的
  4. 不要透露自己的理想薪资(对面试官和hr), 砍价都砍过吧? hr就是这样砍价的, 所以你就不要说你的薪资需求, 简历写“薪资面议”
  5. 一般来说, 设计师的简历是要自己设计的, 如果你懒得设计就去超级简历, 不要写word了, 求求你们了, 写word的简历直接丢垃圾桶
  6. 问好五险一金, 是否大小周, 加班费, 节假日福利, 这些都问好, 作为参考价值, 是属于工资之外的附加条件

结束

暂时想这么多, 如果有想知道其他方面, 就给我评论发消息吧, 设计的文章我以后基本也不会出了, 干编程老本行吧~~~